No, I don't think the project will die; I'm sure it will continue to grow. It's no new revelation that the language has a lot of problems. Even when we finally got prepared statements with the MySQLi interface, there were a lot of problems with the way it worked such that writing a thorough DBAL for it was nearly impossible. But lately I've been pretty positive about the direction PHP has been going--with 5.3 came namespaces, lambdas and closures, among other things.
And then I started playing around with these new features. The namespace delimiter is odd, but big deal. Lambdas and closures, though, are broken and useless for anything but the most basic applications.
For instance, I've been messing around a little with Perl and an awesome OO extension for it called Moose. Moose has a ton of features, but one particular feature is Roles. Roles, as defined by the Moose devs, are somewhere between abstract classes and mixins, with multiple inheritance--but more flexible and easier to develop with. You know, pure awesome.
So I set out to try my hand at making something similar to Roles with PHP's new lambdas and closures. That should give me all the power I need to hack something together, right? This is the best I could come up with:
// class used to enable roles for other classes
class Role {
// used by the class the role is applied to
// must be in that class's __call() method
static public function call($obj,$funcName,$args) {
$func = $obj->$funcName;
array_unshift($args,$obj);
call_user_func_array($func,$args);
}
// applies a role to the object.
// for best results, use in the constructor.
static public function apply($obj,$name) {
$mixin = new $name();
foreach ($mixin as $funcName=>$func) {
$obj->$funcName = $func;
}
}
}
// my example role that I want to apply to other classes
class MyRole {
public $yar = 'role\'s test string';
public function __construct() {
// prints a string, including a var from the object
// that is using this role.
$this->roleFunction = function($obj) {
print('This is a role function! '.$obj->blah."\n");
};
// prints the object that is using this role.
// this will also show the methods it has received
// from the role.
$this->printr = function($obj) {
print_r($obj);
};
// a function that gets overridden by Test class's
// native method by the same name.
$this->overriddenFunction = function($obj) {
print("You'll never see this.\n");
};
}
}
// my class that I want to apply a role to. Note the
// call to Role::apply() in the constructor.
class Test {
public $blah = 'test string';
public function __construct() {
Role::apply($this,'MyRole');
}
// overrides MyRole's version, as it should
public function overriddenFunction() {
print("I beat the role's method!\n");
}
// necessary mess to get $object->roleMethod() to work
public function __call($funcName,$args) {
Role::call($this,$funcName,$args);
}
}
$test = new Test();
$test->printr();
The above will print_r the Test object, as it should, including the public attributes that hold the lambdas from the Role. Neat, right?
Well, not really. This is so messy, so impractical. The limitations are ridiculous. For example, the following works:
$someFunc = function() { print('Hello, blog!'); }
$someFunc();
But this doesn't:
$obj = new StdClass();
$obj->someFunc = function() { print('Hello, blog!'); }
$obj->someFunc();
Whoops! That object method doesn't exist! And what about this:
class MyNeatoClass {
public $someVar = 'Hello, blog!';
public function __construct() {
$this->someMethod = function() { print($this->someVar); }
$this->otherMethod = function() use ($this) { print($this->someVar); }
}
}
Neither the lambda nor the closure works.
$this
cannot be used in lamdas or closures. So, when it comes to using these new features with objects, they're quite nearly completely useless. These are just a couple examples of what makes my above attempt at creating Roles broken and useless.And as I mentioned before, this isn't the first time the PHP devs have botched up new features. They seem to be committed to adding "big boy" features, which should be a good thing, but not to building them correctly. This leaves developers--who actually know what these features are and how to use them in other languages--frustrated and disgusted. For what audience are they coding? Do they think Grandpa Jo's 14-year-old nephew, who "builds websites", is going to use closures? No, real developers are going to try to use them, and then give up, because they're useless.
This trend is obviously going to continue. PHP had the opportunity to recover from past mistakes with recent new features. They have not learned a thing from past mistakes. PHP, you are dead to me.