Reply to comment

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.

Reply

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <b> <dd> <dl> <dt> <i> <li> <ol> <u> <ul> <p> <br> <div> <pre> <code> <img><h1><h2><h3><h4> <blockquote>
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options

.