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).
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.