PHP 2.x frameworks and Ruby on Rails
The Web Dev Zone is brought to you in partnership with Mendix. Discover how IT departments looking for ways to keep up with demand for business apps has caused a new breed of developers to surface - the Rapid Application Developer.
Developers that choose dynamic languages as their tool for building websites and web applications are often divided between two different stacks: the Apache and PHP duo, and the Ruby on Rails platform (although this is a simplification of the big landscape. Paul Graham uses Lisp.) In the last years both these environments have evolved very much, also thanks to the on-going competition. Let's try to take a look at these two technologies from a different point of view of the usual one, which is mostly X has this feature that lets you set array values faster than Y! Beautiful!
It has been said ad nauseam that comparing PHP and Ruby on Rails is unfair as one is a programming language and the other is a full-stack framework. In spite of this, we can compare PHP frameworks (which have learned a lot from their first releases) and Ruby on Rails, again not by piling up a list of features, which would be also cluttered by different extensions and plugins. I'm talking about the different approaches taken by PHP and Ruby framework developers.
First of all, you can't talk about Ruby frameworks: you should talk about Ruby on Rails. The main Rails alternative was Merb, an alternative stack (better architected I'll say) than Ruby on Rails, which introduced a lot of new concepts in Ruby platforms. For example, being ORM-agnostic and do not assume that every single application should employ the Active Record pattern.
The result was that Merb got merged in Rails 3, now in beta:
On December 23rd, we decided to end the duplication and the paradox of choice. -- http://rubyonrails.org/merb
It seems that for the Rails world being able to choose between two different solutions is very bad (I'm starting to sound like Terry Chay.) I agree that dividing the efforts of developer between two (or more) different frameworks is not so clever, but there are also other choices than totally incorporating other projects. Different projects mean possibly different directions, which let the developers experiment with new paradigms and use cases (see OSGi in Java with some implementations used for embedded applications, others for IDEs, and so on).
The other publicly available Ruby frameworks are all trying to be lightweight (less than 4K) or are making an arms race to find out who can let you write an hello world application with the shortest command. The exception is Sinatra, but it is not an MVC framework.
The PHP world has taken a different approach to manage the multitude of frameworks that have appeared in response to the raise of Rails (no pun intended): interoperability. Standards for using components from multiple frameworks are emerging. Symfony 2 will use components from Zend Framework, while Zend Framework 2 will integrate Doctrine (2), the standard object-relational mapper included in Symfony.
With the various "2.0" versions of frameworks, most projects are learning from both mistakes made as well as from the usage patters of the developers adopting them. One of those lessons, to my mind, is that no one framework can do it all well and by themselves. I fully expect to see the next generation of frameworks making it trivial to pull features from other frameworks and libraries in order to fill out functionality. -- http://weierophinney.net/matthew/archives/232-Symfony-Live-2010.html
Or we can merge everything together (and God knows how many frameworks are out there. You can guess I'm primarily a PHP guy.) It's the same old plea for orthogonality: independent components that you can swap to form a gazillion of different combinations. I can use Zend with Doctrine 1, or Zend with Doctrine 2, or Symfony with Doctrine 2, or plain old PHP scripts with Doctrine 2, or Symfony with simple PDO, and so on.
It's no mistery that Ruby on Rails makes a point of convention over configuration. Hopefully, everything is decided by convention unless you specify differently: table names from class names, object fields from table columns, and so on.
A bit of automation is not bad while setting up a framework, although I prefer to generate a common setup that I can customize later. However, I often thought that Rails takes this too far. When I generated my first project in Ruby on Rails, I opened up my classic Post class (the same old create-your-forum-with-two-commands example), and it was like this:
class Post < ActiveRecord::Base
Oh thanks, now I'm enlightened. No fields, no scope, no getters or setters. What is going on here? Where is the business logic?
The motto of the second iteration of PHP frameworks is "less magic" (and "less WTF moments"). The problem with pushing conventions all over an application is that when something goes wrong, it becomes very difficult to find out what is not working correctly. It's like having an IDE deploying your application on the live server at the push of a button: apart from the fact that you have no clue on how to introduce customizations in the automated process, you're never going to know what that button does, and if the deployment fails you're left with a standard error message. Netbeans is an IDE that gets it right: it generates an Ant script (usually build.xml) with a list of targets such as build and test, and its buttons simply run this script. You can look at build.xml or even add debugging statement if there are issues, while hacking in a framework's automagic code open a big a can of worms.
Another example of less magic in PHP (and also in Rails, as Active Record will not be forced upon the developers in 3.x) is the current transition from Active Record with public properties to DataMapper-based entities that expose getters. In Doctrine 2, the use of getters lets the framework override them in custom subclasses that are saved in a folder specified via configuration. These subclasses are proxies - they take the place of entitites that may not be accessed and when the getters are called, perform lazy loading of the fields. And you can hack them for debugging if something does not add up.
Sure, in PHP the same can be obtained with __get() and __set(), but then we'll have the following use case:
echo $post->title; // giant database query ensues
And when you lose the distinction between properties and methods, you have some magic that is going to bite.