Comments about PHP's New Lambda and Closure Features

I've been reading up on it, and, not being up-to-date on PHP development news, didn't know about the discussion about the design on PHP's new lambda and closure features in 5.3.

A few things jumped out at me that seem a little wrong.

First, if a lambda is defined in a class, it includes a reference to $this, making it a closure. In this example, method returns a lambda.

class A { 
   function method(){ return function () { echo "hi"; } }
}
$a = new A();
$m = $a->method(); // is now a function that prints "hi"
$a = null; // this removes the reference to the object
$m(); // prints "hi".

Now, $m contains a reference to the object A that was created before. $m is a closure -- a closure is a lambda that includes a table of local variables.

Clearly, we don't need the $this object around for $m to execute. So, we're supposed to use the static keyword to prevent $this from being included in the closure.

class A { 
   function method(){ return static function () { echo "hi"; } }
}

That seems odd to me. It seems that if you want to use $this, you should explicitly "use" it, like this:

class A { 
   function method(){ return function () use (&$this) { echo "hi"; } }
}

That would be more orthognal, imnsho.

Maybe they were trying to reduce the typing.

Reflection

Another interesting thing they did was add the __invoke() magic method. This is a functor method. I'm not sure why they included it with lambdas, but, it's there.

Now, you can do this:

class A {
  function __invoke() { echo "hi"; }
}
$a = new A();
$a(); // prints "hi"

This is cool for things like arrays, because you can put the lookup functionality into the __invoke() function, and your code looks like this:

for($i;$i<10;$i++){
    $o = $objects($i);
}

Instead of $objects->find($i), you type $objects($i). Shades of Visual Basic and C# here, but good ones.

Now, what I don't get is that they added a new method to ReflectionMethod called getClosure().

getClosure creates a closure out of the method, so you can invoke it. The old way was to use invoke(), like this:

$cl = new ReflectionClass('classname');
$meth = $cl->getMethod($cl,'method');
$meth->invoke( $args );

The new way is:

$cl = new ReflectionClass('classname');
$meth = $cl->getMethod('method');
$closure = $meth->getClosure();
$closure( $args );

Okay, maybe that's nicer. It seems more verbose.

What i don't understand is why they did't simply define __invoke() of ReflectionMethod to work like invoke(). Then you could say $meth($args), and it would be invoked. No need to create the closure.

Of course, that would only work for static methods.

The getClosure() method can take an object reference as a paramter, and it becomes $this in the closure. I just don't see a situation where this is useful. Maybe I'm missing something.

It seems like the getClosure($obj) form is just doing something like this:

$closure = function ( $x ) use ($object) {
    $object->method( $x );
}

Granted, with reflection, you can specify the method name at runtime, and the above code doesn't do that. This code below does:

$closure = function ( $x ) use ($object, $methodName) {
    $object->$methodName( $x );
}

Maybe I'm not getting what they're doing.

Maybe they've worked out some things where they do a lot of runtime object composition, and it get easier if you have getClosure() instead of writing it in longhand.