Analysis: Following Ruby Makes PHP Number Two
These days, people sure seem to be coming up with some… interesting names for their projects. Dennis Hotson, for example, wrote in his blog today about PHP Object Oriented Programming Reinvented.
That’s right—PHPOOPR.
Dennis acknowledges that the name needs work. But, getting past that, his blog is about some creative experiments Dennis is working on. He has come up with a pretty innovative way of creating objects dynamically in PHP that allows for some usage that conventional PHP coding techniques don’t support:
- Classes can be hacked / patched / cloned. Methods can be added to classes at any time.
- Classes can be scoped. They’re not global, unless you want them to be.
- Classes can be temporary (and garbage collected).
In Dennis’s code, class definitions are objects themselves, created by a base class constructor function Obj()
.
$class = Obj();
A Factory is a design pattern for an object that can create more objects of various types. Thus, Obj()
is a factory method.
The only thing that differentiates one class instance from another is the methods it supports. You can add new methods to any class by passing a PHP closure to a class object.
$class->fn('new', function ($class) { $newClass = Obj($class->methods) ->fn('new', function($class) { $obj = Obj($class->imethods); $args = func_get_args(); array_shift($args); call_user_func_array(array($obj, 'init'), $args); return $obj; }); return $newClass; });
Now, $class
can create instances of the respective type, so these class objects are also factories, making Obj()
a factory factory.
$object = $class->new();
You can make a class support subclassing by adding a new method to return a new class object, a clone that has the same functions:
$class->fn('extend', function($t) { return clone $t; }); $subclass = $class->extend(); $object = $subclass->new();
Since all classes are factories, extensible classes are therefore also factory factories. Which makes Obj()
a factory factory factory.
You can add more methods to each class instance, of course.
This is a very clever experiment. But I wonder if Dennis wants to program in the paradigm of everything-is-an-object like Ruby or Python, why doesn’t he just use Ruby or Python?
His experiment mimics what those languages have already done, but he still has some parts of PHP that developers hate, such as the motley, non-OO built-in functions, and the need for the array()
syntax for array literals.
There are a number of other features of PHP’s conventional OOP that go out the window in Dennis’ code:
- Compile-time typehints: Classes don’t even have names, they only have instances, which aren’t created until runtime.
instanceof
: Likewise, you can’t test an object’s class for its type or any of its supertypes because types don’t have names. An object doesn’t know what type it is, only what methods it has.- Interfaces: Dennis doesn’t show how one would force an object to have a certain set of methods to conform to an interface, or how to make any given method have a specified signature.
- Reflection: PHP’s built-in functionality for reporting meta-information about types doesn’t work with Dennis’ objects, so he’d have to reinvent that wheel.
- SPL: All the types in SPL rely on conventional class extension and interface implementation, so they’re incompatible with Dennis’ objects.
- Autoloading: PHP loads a class automatically if you reference it by its name, but if classes have no name, you have to take responsibility for loading the code that creates classes yourself.
===
: The idea of type equivalence is blurred. Two objects are “the same” if they simply have the same set of methods.- Code completion: In the same way that an IDE can’t infer the methods of an object implemented through the magic method
__call()
, these dynamic objects have functions that are not known until runtime, so intellisense has no idea what methods exist or what their signatures are.
The experiment Dennis is coding is worthwhile, but not because it will be useful. Instead, it’s worthwhile because it illustrates how we rely on the concept of a type in a programming language. Types enforce structure and help us depend on certain assumptions (like the interface of a class), so we can write simpler code. If we have limitless flexibility, we can’t rely on any structure remaining in place, so we have to write more complex code to handle an increasing amount of uncertainty and variation.
[Updated 09/28@18:52ET to fix the spelling of Dennis’ last name (with our apologies)]
Leave a comment
Use the form below to leave a comment:
Responses and Pingbacks
September 23rd, 2010 at 12:51 pm
We are charging too much for a project that arose a few days. We must invest in the idea, the dynamics that it offers. If it really is worth investing, the factors you pointed out is only a matter of time that support them they will exist. But I agree with you when comparing this experiment with Ruby and Python.
September 23rd, 2010 at 7:34 pm
Thanks Bill. You make some excellent points.
In my defense, I think it’s a pretty good result for 90 lines of PHP. There’s plenty of stuff I didn’t implement because I really just wanted to try out a few core ideas.
Also, in case I wasn’t clear: It’s just a hack and I wouldn’t recommend using it in any way. Please just enjoy it as a piece of code origami. 🙂
September 23rd, 2010 at 7:59 pm
Hi Dennis, thanks for your comment. I sure did enjoy your code, it was a very clever exercise.
Another programming language that your experiment reminded me of is LISP. Have you ever looked into that seriously? You might enjoy it.
September 24th, 2010 at 1:28 am
Greattt!!
When to use ruby + PHP?
September 24th, 2010 at 6:57 am
thanks… your points were great…
i could use them on my research…
September 24th, 2010 at 10:39 am
I think the same argument you are making about Ruby and Python could be applied to PHP itself. If you need all the structure (interfaces, abstracts, types, etc) of conventional OOP, shouldn’t you be using Java, or C#, or some other compiled language that can stand the overhead of all that structure without having a serious impact on application performance?
September 24th, 2010 at 11:21 am
Edward: Excellent point, couldn’t agree more.
Bill: Was this blog post really necessary? It’s clearly intended to be an experiment, and as you said yourself, it’s a clever idea. The author never says we should all go out and start writing code that way.
Also, unless you have a fanboy’s attitude, there’s no war between PHP and Ruby. Tilting at windmills (and the attempt at a provocative title) just makes you look bitter.
September 24th, 2010 at 1:00 pm
@Edward Vermillion: Thanks, it’s true there are degrees of how the language deals with types. Java or C# are more strongly typed than most dynamic languages, and that means those languages can do some things that others can’t. But coding in these language is also more meticulous. So there are tradeoffs.
@Nate Abele: This blog post was not a disparagement against Ruby or Python. The idea behind this blog post is that no matter what programming language you use, types must have names. It’s crucial to the nature of being a type. Even in languages that favor duck-typing, like Ruby and Python, classes have metadata.
September 28th, 2010 at 8:21 am
Talking about the code itself isn’t this similar to PECL runkit?
September 29th, 2010 at 10:39 am
@Nate Abele: Make your words my.
@Bill Karwin: It’s only a experiment. Don’t take it so serious. Just like every day there are new frameworks with different proposals and dynamics, why Dennis Hotson can’t propose anything new? Use whoever, nobody is forced.
September 29th, 2010 at 11:17 am
@Igor: Thanks for your comment. I agree with you, and I encourage people to make experiments. Nowhere did I say Dennis or anyone else must not experiment in this way. I only described the consequences if one does use his technique.
If you interpret my description as a prohibition against using the technique, then this just shows that its consequences are worth avoiding.
October 1st, 2010 at 11:04 am
The information is very useful to me and to my students.
October 5th, 2010 at 7:47 pm
@Lloyd Watkin: Good point! PECL runkit provides some of the same features, such as the ability to add methods to a class at runtime. But classes remain compatible as native PHP classes, so you can still perform reflection and all the other features I mentioned.
October 22nd, 2010 at 3:30 am
“Good point! PECL runkit provides some of the same features, such as the ability to add methods to a class at runtime. ”
True!
http://www.smithmonitoring.com
November 16th, 2010 at 11:52 am
Excellent point,Bill.I totally agree.
November 21st, 2010 at 10:20 am
If you interpret my description as a prohibition against using the technique, then this just shows that its consequences are worth avoiding.
November 30th, 2010 at 8:21 am
“Good point! PECL runkit provides some of the same features, such as the ability to add methods to a class at runtime. But classes remain compatible as native PHP classes, so you can still perform reflection and all the other features I mentioned.” You made excellent point here Bill.I can’t agree more with you!
December 23rd, 2010 at 9:24 pm
The information is very useful to me and to my students.
July 8th, 2011 at 5:49 pm
Keep these ariltecs coming as theyve opened many new doors for me.