New magic methods are awesome
The past couple days, I worked again on the little Sinatra-like DSL thing I mentioned before. It makes use of the new PHP 5.3 features. The ones I really love are the new magic functions __invoke and __callStatic. Invoke allows you to call an object instance like a function, e.g.
$front = Front::getInstance();
$front('/')->get(function () { echo 'hello world!'; });
// this is how my little DSL project is invoked at the moment.
and __callStatic allows you to catch all undefined static method calls, which is very handy for singletons.
class Front {
// this is a singleton
static public function __callStatic($method, $args)
{
return call_user_func_array(array(static::getInstance(), $method), $args);
}
}
Front::setParam('foo', 'bar'); // this is the same as Front::getInstance()->setParam('foo', 'bar');
(Update: meh, I spoke too soon. The example above doesn’t pass through __callStatic if there is an instance method setParam. It works because PHP allows instance methods to be called non-statically along with a strict notice. Note to self: test first before making claims.)
In addition to singletons, __callStatic could be used in ORM or table gateway finder methods.
$user = User::findByEmail('foo@example.com');
// would return a row object
// whereas before you need to instantiate a User first before finding.
But you know what would really be nice? A combination of the two.
class Hello {
static public function __invokeStatic($name)
{
echo 'Hello, ' . $name . '!';
}
}
Hello('mon'); // Hello, mon!
It might look retarded because you could just define a Hello($name) function and accomplish the same. The reason I think this feature is reasonable is the inability to import and alias namespace functions with the use keyword. For example,
namespace greet {
class Hello {
static public function __invokeStatic($name) {
echo 'Hello, ' . $name . '!';
}
}
function hi($name) {
echo 'Hi, ' . $name . '!';
}
}
namespace somethingElse {
use greet\Hello as hey; // you cant use greet\hi
hey('mon'); // Hello, mon!
\greet\hi('mon'); // Hi, mon!
}
How I wish this were possible. I dislike the namespace separator (although a lot less now than before) and I’d like to limit the use of it in the use and namespace declaration only. Also, it is easier to maintain state with a static class function rather than a namespace function because namespace variables are actually globals. These two reasons really make namespace functions undesirable for me, and I imagine others would find the same once 5.3 becomes prevalent.