Why MVC doesn’t fit the web

[MVC is] a particular way to break up the responsibilities of parts of a graphical user interface application. One of the prototypical examples is a CAD application: models are the objects being drawn, in the abstract: models of mechanical parts, architectural elevations, whatever the subject of the particular application and use is. The “Views” are windows, rendering a particular view of that object. There might be several views of a three-dimensional part from different angles while the user is working. What’s left is the controller, which is a central place to collect actions the user is performing: key input, the mouse clicks, commands entered.

The responsibility goes something like “controller updates model, model signals that it’s been updated, view re-renders”.

This leaves the model relatively unencumbered by the design of whatever system it’s being displayed on, and lets the part of the software revolving around the concepts the model involves stay relatively pure in that domain. Measurements of parts in millimeters, not pixels; cylinders and cogs, rather than lines and z-buffers for display.

The View stays unidirectional: it gets the signal to update, it reads the state from the model and displays the updated view.

The controller even is pretty disciplined and takes input and makes it into definite commands and updates to the models.

Now if you’re wondering how this fits into a web server, you’re probably wondering the same thing I wondered for a long time. The pattern doesn’t fit.

Read the rest at Why MVC doesn’t fit the web.

Beta2 of pds/skeleton now available!

I am excited to announce that pds/skeleton 1.0.0beta2 has been released. (The pds/skeleton publication describes a standard PHP package skeleton, as backed by research into the PHP package ecosystem.)

Among other things, this release incorporates some command-line tooling to validate, and generate, your PHP package skeleton.

Barring unforeseen events, I expect the next release to be stable.

Thanks to everyone who made this release possible, both direct contributors, issue reporters, and everyone who commented on the research!

RFC: ServerRequest and ServerResponse

The RFC is at https://wiki.php.net/rfc/request_response.

The message opening discussion on Internals is at http://news.php.net/php.internals/97461.

The extension itself is available at https://pecl.php.net/package/request, with documentation at https://gitlab.com/pmjones/ext-request.

(Many thanks to John Boehr for doing the actual heavy lifting of writing the C code.)

Nearly every PHP framework and library-collection since 2000 has had classes to encapsulate the “request” and “response” elements of a PHP application. A handful of examples include:

There are many others. They all do essentially the same things:

  • Copy the $_GET, $_POST, $_SERVER, etc. superglobals into a “request” object. Some make them available through a method that standardizes the logic to get a default value when a key is not present, a la return (isset($_GET[$key]) ? $_GET[$key] : $defaultValue).

  • Add convenience methods to the “request” object so that you can determine the HTTP method, the values of various headers, and so on.

  • The “response” object is a place to hold headers, cookies, status, and content, so they can all be inspected and modified before sending, and to make testing easier. (This is because the header(), setcookie(), etc. functions in PHP are not especially amenable to inspection, modification, and testing – at least, not without being wrapped somehow.)

  • The “response” object often has some convenience methods to send JSON content, send files for download, and so on.

Why do framework and library-collection authors write these request and response objects? Because PHP, even though it is a web-centric programming language, and even though it provides all sorts of classes for all sorts of functionality, it has never had classes for server-side requests and responses. This RFC helps to improve this situation in PHP 7 and later.

Definition of “Done”  in a web project

– Source code meets our coding standards.

– High enough level of unit test coverage for routes, action methods and controllers.

– High enough level of unit test coverage for business logic and repositories.

– High enough level of automated UI and integration test coverage.

– Code has been peer reviewed.

– Code must be completely checked in to the source control system and the build and all the automated tests should be green.

– UI looks nice and works on different resolutions on major browsers and browser editions.

– UI fulfills the accessibility requirements.

– UI works with and without javascript enabled.

– End user help/documentation/tooltips are done.

– Any auditing/tracing code is added and the output is useful and readable.

– Security permission checks have been implemented and validated via automated tests.

– Automated database migration scripts are provided and testedSample data needed to test the feature is scripted, if required.

– Users have tested the feature and are happy with it.

I’ll nitpick and note that “MVC” is not an application architecture, but whatever. Source: Definition of Done in an MVC project

New Releases, and Collected Content

Some quick notes from the past few days about various projects:

  • The core Action-Domain-Responder implementation package for Radar has had its first beta release. (I’ll be able to release a stable version when the various pacakges it requires go stable as well, Aura.Di 3.x being the most relevant.)

  • The core implementation package of Bookdown, the DocBook-like documentation generator that uses Markdown and JSON instead of XML, has had its first beta release as well.

  • We released Aura.Filter 2.1.0 with new isNotBlank() functionality. Have I mentioned that it has what is probably the most thorough email validation in PHP-land? (And really good UTF-8 support as well.)

  • We’re starting on the 3.x version of Aura.Sql, which provides a bunch of convenience functionality around PDO. This new version starts off by providing yield*()generator methods; you can use those instead of fetch*() to conserve memory when working with larger data sets.

Finally, I have added a ton of content and resource links to this blog:

  • under appearances you will find lots of podcasts I’ve been invited to;

  • code lists all my current and past projects;

  • community lists some of my community work;

  • talks reveals almost every presentation I’ve ever given, with slides and recordings when available;

  • and writing collects my various technical publications into one place.


“Page Script” As A Degenerate Controller

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
require_once '../setup.php';

// dependencies
$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
$view->assign('records', $records);
$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.

[mc4wp_form id=”5830″]