Kill your index.php

29 Jan2014

Although not all PHP frameworks are "Rails clones", the history of modern PHP frameworks really begins with the rise in popularity of Ruby on Rails.

Until Rails started to gain serious mindshare amongst developers and market share amongst consulting clients, no-one was really talking about using MVC patterns in PHP applications.

If you look at the list of frameworks on http://www.phpframeworks.com/ (which is pretty old) you find that PRADO was the only framework that was released before Rails became popular (it was released about the same time as Rails), and one of the only ones that doesn't cite Rails specifically as an inspiration[1].

Most importantly, Rails brought a term into the web vernacular in a big way and that was "MVC".

Even though Java's Spring MVC framework was released well before Rails You can see that the release of Rails had an impact on the popularity of people looking for "spring mvc":

CMS added image

The appeal of index.php

The core idea of a web developmernt framework is to improve developer productivity by:

  • Automating or simplifying repetitive tasks, making them both faster and less error prone
  • Making it easier for multiple developers to collaborate on the same project

Every PHP framework I've ever come across includes in it the main "entry point" for the application, usually called index.php or something similar.

The PHP framework zeitgeist was very heavily influenced by the Rails MVC and ORM models and implementing this without a central "application entry point" seems clunky.

You don't want to "spoil the illusion" that we're working in a purely object orientated environment by exposing the developer to some procedural application entry point (this could well be Java's influence, which took the C language's "main" function and hid it from the developer altogether).

I know this in part because I fell victim to the same thinking.

"Projects which were, according to the collective wisdom of the time, terribly written "spaghetti code" were in fact the easiest to understand, fix and modify."

I had been working on some framework-like ideas and when Rails was released a lot of these ideas were included in my own framework called RocketSled.

The first versions of RocketSled were a hideous, monolithic beast that never gained any traction with anyone except me.

Following the development of a few larger web applications I started to re-think how I wanted to structure my code.

One of the biggest realisations I had was that making PHP application structures more "standardised" was not succeeding in creating something on which it was easier for a range of different developers to collaborate.

The more I started working with other people's code, maintaining existing projects, fixing problems on websites that had been abandoned by other developers and working with frameworks I had not written myself, I realised that the more cleverly written an application was, the higher the barrier of entry for me to understand it so I could fix bugs or make changes.

Projects which were, according to the collective wisdom of the time, terribly written "spaghetti code" were in fact the easiest to understand, fix and modify.

Around the same time, I started lurking in #stackvm on freenode and looking at the way James Halliday (aka Substack) and Peteris Krumins were writing their software using "very small modules" and began thinking about how I could strip everything away from RocketSled and what a truly minimalist PHP "framework" would look like.

Here's a rough bullet list of what I wanted to achieve:

  • I wanted a framework that did almost nothing: no templating, no URL structure, minimal routing, no package management; all this stuff should be the job of "userland" packages so you can pick and choose what you wish to use easily at any time in a project's lifecycle
  • Whatever it did do, should be completely optional. You should be able to override whatever default behaviour is provided "out of the box" as and when it becomes convenient to do so; if some feature of the framework stops being a help and starts being a hindrance, you should just be able to leave it behind and do something else
  • You should be able to hack things together however you want in order to get the job done (arguably one of the core philosophies of PHP as a language)
  • I wanted to have a system for installing little modules (similar to Node's npm)
  • I wanted to make use of the __autoload feature (PHPs strongest feature IMHO[2])
  • I wanted to make it simple to use the huge body of PHP code already written, without having to modify it to fit in with the framework
  • I didn't want the code that I wrote to be tied to any framework

I had already banished the concept of using a templating engine in favour of Template Animation so any benefits that existing frameworks had to offer around structuring views or providing a "separation of concerns" between business and display logic were a non-issue.

As I toyed around with this concept I started writing the first versions of the newly stripped back RocketSled, and a package manager called RocketPack which would install code from git repositories and manage dependencies.

Source code management: the thorn in my side

I wanted to be able to install the framework code and leave it completely unmodified, then have all my code, configuration etc. happen in "userland" packages which would have their own source control repositories (I use git but whichever SCM tool you use the principle is the same).

This inevitably lead to all sorts of directory scanning to find configuration files and various code location configuration options so that I didn't have to alter the RocketSled code once it was installed.

In order to resolve this issue, I started coming up with a directory schema and configuration "injection" system, but I couldn't seem to come up with anything that just didn't feel like a rehashing of the same old "directory structure dictatorships" common to every other PHP framework in existence.

Nothing I came up with truly addressed my goals of having something that was essentially invisible, essentially meaningless and essentially not a framework.

"Once you take away package management, templating and routing (all of which I wanted to be the responsibility of interchangeable userland packages) what does a framework really do anyway?"

Before Rails, there really wasn't a way to write web applications in Ruby. Before Django, there really wasn't a way to write web applications in Python.

That's when I realised that what others had been saying for so long is true: that PHP is a framework.

Why was I so hell bent on having an "index.php" as part of a PHP framework rather than as part of the application code for the project I was building? Why did my "framework" have to provide the main application entry point?

Rails and Django only did for Ruby and Python what PHP had already done for itself, but the structure of those frameworks made the PHP community jealous. Everything looked so well organised and clearly documented. PHP raced to catch up; raced to be as MVC as Rails.

When I examined the applications we'd built with this new version of RocketSled the config files that were contained within each package were just arbitrarily formatted PHP files, and I'm a huge fan of PHP as a configuration language in PHP projects (rather than having configs written in JSON or YAML or XML or whatever). The configuration files were all pretty minimal, and were just chunks of "procedural" code to define constants or include required files (such as autoloaders for other packages).

Whilst I was trying to come up with some clever way to prevent the developer from ever having to touch the YUCKY and PROCEDURAL index.php file with a weird concoction of directory schemas and configuration injection points and directory scanning, I could much more easily just create tools that did some stuff that I found repetitive and define a simple way to use them from any application (ie. from an "index.php" not under the control of the "framework" itself).

Once you take away package management, templating and routing (all of which I wanted to be the responsibility of interchangeable userland packages) what does a framework really do anyway[3]?

So I refactored RocketSled into what it is today: a non-framework tool for managing your autoloading class paths in a way that's completely override-able by anyone who chooses to use it and that doesn't interfere with the way that any other class loaders you might wish to use already work.

Unfettered by the shackles of my "index.php" rewriting RocketPack to be a standalone package management tool for git repositories became a triviality.

I then came up with a basic "boilerplate" for using RocketSled with RocketPack and put that into it's own repository at https://github.com/iaindooley/RocketSledBoilerPlate.

The key here is that RocketSled and RocketPack themselves are completely independent of the methodology used in RocketSledBoilerPlate. You could come up with your own RocketSledBoilerPlate. I can change my mind later on pretty easily: none of the code I've written has any dependency on this way of doing things.

If I want to use a PHP package that already exists, I just have to include the autoloader/bootstrap file provided by that package. I don't have to worry about changing that package to fit in with my framework at all.

The workflow we follow now is:

  1. Clone the boilerplate
  2. Create a new repository using these files
  3. Modify the code as required

One could argue that I have broken my original rule of "not modifying the framework" code, but the code contained within the RocketSledBoilerPlate project is so minimal that I don't really see this as an issue.

[1] Symfony is another but you can find empirically that there was a big influence on Symfony from the rise in popularity of Rails [take me back to where I was]

[2] I'm obviously not the only one who thinks so, either. Check out this fantastic article from the team behind Propel: http://propelorm.org/blog/2011/03/21/the-end-of-autoloading.html [take me back to where I was]

[3] I think there is a common move towards this non-monolithic style of framework. For examples, check out this post by Fabien Potencier on what Symfony2 is: http://fabien.potencier.org/article/49/what-is-symfony2 and this fantastic talk by Kenneth Reitz "Flasky Goodness (or why Django Sucks)" http://www.youtube.com/watch?v=U2frH932U1g [take me back to where I was]

This entry was posted on Wednesday, January 29th, 2014 at 9:20 am php, programming, programmings, techniques, technique

blog comments powered by Disqus

Subscribe

Subscribe via RSS

Building software in the real world - the Working Software blog

We write about our experiences, ideas and interests in business, software and the business of software. We also sometimes write about our own products (in order to promote them).