Rails Principles in PHP

Posted 27 September 2006 under , ,

I was recently contracted to develop a CRUD web application for a local non-profit. After spending the last few months developing with Ruby on Rails at work, imagine my dismay when the project specifications called for the site to be written in PHP. I looked at a few PHP-based Rails knockoffs — CakePHP and PHP on Trax (/gag) — but I couldn’t see myself using either of them to create a production web application. Both contain a lot of good ideas, but for all of the similarities between these frameworks and Rails, what really stood out for me were the differences. To paraphrase one Digg member, “One of the best features of Ruby on Rails is Ruby.”

However, as development on the project has proceeded, I’ve found myself pulling various Rails principles into the PHP implementation, with (imo) positive results. Even the file structure of the application resembles that of a Rails app, with directories for models, views, and presentation resources (stylesheets, scripts, images). What follows are some of these concepts. As a note: “Rails principles” is something of a misnomer; it’s probably more accurate to call most of them simply good principles.

MVC (Model-View-Controller)

From Wikipedia:

Model-view-controller (MVC) is a software architecture that separates an application’s data model, user interface, and control logic into three distinct components so that modifications to one component can be made with minimal impact to the others.

A typical PHP application is made up of a series of pages, each of which performs multiple tasks. A page might receive input from a form, validate it, insert it into a database, and then display the results, pulling in a header and footer from external files. As you can imagine, this leads to a lot of inflexibility and redundant code. What if the user submits bad data? What if the database schema changes?

Following the MVC pattern, data and logic are isolated from the user interface. All requests go through a central controller, in this case, index.php. The controller receives requests and their associated parameters, determines what actions to perform, and then works with the models to execute them. Each model, representing an object stored in the database, has methods for creating, updating, and deleting records, as well as formatting and validating data and reporting errors. Model classes also have static methods for finding an object by its ID number and getting a list of all instances of that class.

Depending on the success or failure of the intended action, the controller then determines what view to render, and with what information. If the user intended to create a new record, but failed to fill in a required field, the controller sends the user’s input, along with a friendly reminder, to the record creation page. Once the user makes the correction, and the record is stored in the database, he will be sent to the new record’s page with a message indicating his success. Such flexibility would be difficult to accomplish in a more page-oriented architecture.

Code reuse

Like Ruby on Rails, each model class extends a generic Model class that contains functions for the storage and retrieval of database records. This way, when I want to create a new stored object, I only have to create the new class, point it to the corresponding database table, and create custom methods for data formatting and validation. Additionally, a lot of views can be reused — if the data is the same, there’s no sense in storing two forms for creating and updating records when one will suffice.

Flash notices

A great feature of Rails is the flash[:notice] variable, which can be set to display a message the next time a view is rendered. I’ve found such functionality invaluable for describing the results of an action to the user in meaningful way, and thus I’ve duplicated it for my current project. Here are two such messages, for when a user attempts to make an invalid update …

And a valid one …

Here’s the rub

One major stumbling block I’ve encountered has to do with the way PHP handles inheritance of static class methods. Consider the following Ruby class definitions:

class Car
  def Car.showClass
    puts name
  end
end

class Hotrod < Car
end

And the equivalent in PHP:

class Car {
  static function showClass() {
    echo get_class();
  }
}

class Hotrod extends Car { }

Calling the Ruby functions gives the expected results:

> Car.showClass
Car
> Hotrod.showClass
Hotrod

But in PHP

> Car::showClass()
Car
> Hotrod::showClass()
Car

¡Qué mala suerte! RoR’s find() function, pretty much called whenever you want to do anything, depends on classes having some sense of self-awareness. This doesn’t translate so well into PHP, where it seems that classes, like half of my private school classmates, can only tell you who their parents are. I’ve developed a workaround, but it’s not as pretty as I’d hoped.

Further reading

In case I haven’t convinced you I’m the biggest geek in the world:

There’s a lot to love about PHP; it has transparency, stability, and hosting support that Ruby on Rails, in its current iteration, can’t match. Add in some of the standout features of the Rails framework, though, and the result is a much stronger (cleaner, more organized) final product.


About Me

I’m the Development Director at Viget in Durham, North Carolina. I’m also an avid reader, traveler, cyclist, musician, coffee fiend, and friend of birds.