PHP’s object inheritance problems
Soledad PenadĂ©s says that “PHP will never have a (real) Rails-like framework” because the language does not allow classes to be modified after they’ve been defined. Which is true, and she’s right. I’m not sure how instructive it is to say that you can’t make Ruby on Rails with PHP, since the framework succeeds primarily because it was built with Ruby. It’s a bit like claiming that no boat will ever win the Indy 500.
If the question were, instead, can you build a competent MVC framework with PHP, then the answer is yes, definitely. There are hoards of evangelists for most existent PHP MVC frameworks, and there are scads of other homegrown solutions waiting to be advocated.
The real issues here are the shortcomings of PHP’s object implementation, and the problem doesn’t lie in the ability to extend its classes after they’re defined. The real problem is how to extend PHP classes during definition. More specifically, the problem is the one-to-one inheritance system that PHP requires.
Ruby’s mixins — and multiple inheritance in other languages — mean that a Model class can inherit methods from the HasChildModel class, as well as the HasAWifeModel class and the HasADogAndACatModel class. And the nature of mixins means that another Model class can HaveAWife and HaveAChild but not HaveADogAndACat, which is extremely convenient for Model classes that live in small city apartments. For this to work in PHP, however, all these classes have to be daisy-chained together in parent-child relationships, like an Old Testament verse: Model begets HasAWifeModel begets HasAChildModel begets HasADogAndACatModel, and lo unto the Model that wants pets without the hassle of getting married.
What’s more, once you define these relationships, there’s no backing out of the chain. If class A extends (inherits the properties and methods of) class B, which itself extends class C, there’s no way to get an object of class A without getting the baggage that B and C add. Which is probably fine. But if the time should come that you’d like a class A that extends class D, then you’re forced to write a whole new class definition of A, with all its method duplicated and with a brand new class name like AFromD, all just to bypass the mess you got yourself into by getting mixed up with those layabouts B and C. By the immutable laws of PHP, “A extends B” is writ in stone, nothing under D’s green earth can tear it asunder.
What PHP needs is something like Ruby’s mixins, but what it has instead is something called an interface, which a class may implement alongside other interfaces, but which offers only a blueprint for methods and properties a class must define on its own. If PHP interfaces were allowed to bring their own methods and properties to the party, then we could have a class A which gained the methods of class D without having to define them itself, and HasAWifeModel could finally gain the methods of HasADogAndACatModel without having to resort to becoming a HasAChildModel, which truth be told he’s neither financially nor emotionally ready for.