I read a good conversation on Reddit last week titled Thoughts on MVC vs. Pages for Everything?. Short version: the OP asks about the advantges of using a formalized model-view-controller system vs a series of typical PHP page scripts. The entire discussion is worth reading.
As the author of a book on modernizing legacy applications in PHP, this is a topic I am very familiar with. Almost all of the legacy applications I’ve had to deal with were page-based. In doing the work to modernize them, there comes a time where the page script has been refactored to look very much like a page controller, with some distinct but not critical differences. As such, I have come to consider the typical PHP page script to be a degenerate form of a page controller. With a little imagination, I think it’s easy to see why.
First, recall the basic operational cycle of almost every PHP framework ever, including the micro-frameworks:
a bootstrap index.php file that does some setup work, which hands off to …
a front-controller (typically a router/dispatch system) which picks …
a page controller or action method that calls services and collates the results into a data structure, which is passed to …
a view layer that renders the results for the client.
(In an earlier version of this dispatch cycle I split “page controller” and “action method” into two separate steps, and in many cases they may still be two separate steps.)
When we look at this cycle, it’s not so hard to envision a plain PHP script doing the same things. The web server itself becomes a simplified front controller+router+dispatcher, picking the “controller” (page script) to run based on the URL path mapped to the file system. After that the work is exactly the same, albeit combined into a single blob of code.
Even then, the page script can keep itself in good order by using service objects instead of embedding all the logic in one place. It should be easy to imagine converting a page script that combines the setup, data retrieval, data manipulation, and data output concerns as a blob of intermingled code, into something more like the following, where the concerns are in blocks:
// config, global vars, autoloader, etc
$request = new Request($GLOBALS);
$response = new Response($GLOBALS);
$db = new Database($user, $pass, $host);
$service = new Service($db);
$view = new View;
// data retrieval
$page_number = (int) $request->get('page', 1);
$records = $service->fetchPage($page_number);
// data rendering
$content = $view->render();
// send back to client
That page script is not wildly different from what goes on inside a formal MVC framework. Yes, there are still some legacy elements. These include the global require setup at the top, the use of query parameters instead of path-info parameters, and the lack of a formal DI container (although for scripts like this a container proper might be overkill at the start).
On the other hand, most of the work is being done in classes and objects, not embeddded directly in the page script itself, just as you would see in a formal controller class method. These support classes and objects are independently testable; only the page script “controller” itself is not. But be honest here: of all the formal controller methods you have seen in the wild, how many were independently testable? My guess is “not many.”
Once we have refactored a page script to something like the above form, it becomes a lot easier to see how we might convert this degenerate controller over to a formal MVC framework with even further separation of concerns.
Are you overwhelmed by a legacy application full of page scripts, spaghetti includes, and global variables? Do you want to improve the quality of the code, but don’t know where to begin or how to proceeed?
My new book, Modernizing Legacy Applications in PHP, gives step-by-step instructions on how to get your code under control and keep your application running the whole time.
Buy the early access version now and get free updates as it is completed, or sign up on the mailing list below for more information and a free sample chapter.