I see that the new planned features for PHP 5.4 are: traits, array dereferencing, a JsonSerializable interface and something referred to as 'closure $this support
'
http://en.wikipedia.org/wiki/Php#Release_history
While the others are either immediately clear (JsonSerialiable, array dereferencing) or i looked up the specifics (traits), I am not sure what 'closure $this support' is. I have been unsuccessful googling for it or finding anything about it on php.net
Does anyone know what this is supposed to be?
If i had to guess, it would mean something like this:
$a = 10; $b = 'strrrring';
//'old' way, PHP 5.3.x
$myClosure = function($x) use($a,$b)
{
if (strlen($x) <= $a) return $x;
else return $b;
};
//'new' way with closure $this for PHP 5.4
$myNewClosure = function($x) use($a as $lengthCap,$b as $alternative)
{
if(strlen($x) <= $this->lengthCap)) return $x;
else
{
$this->lengthCap++; //lengthcap is incremented for next time around
return $this->alternative;
}
};
The significance (even if this example is trivial) being that in the past once the closure is constructed the bound 'use' variables are fixed. With 'closure $this support' they are more like members you can mess with.
Does this sound correct and/or close and/or reasonable? Does anyone know what this 'closure $this support' means?
This was already planned for PHP 5.3, but
For PHP 5.3 $this support for Closures was removed because no consensus could be reached how to implement it in a sane fashion. This RFC describes the possible roads that can be taken to implement it in the next PHP version.
It indeed means you can refer to the object instance (live demo)
<?php
class A {
private $value = 1;
public function getClosure()
{
return function() { return $this->value; };
}
}
$a = new A;
$fn = $a->getClosure();
echo $fn(); // 1
For a discussion, see the PHP Wiki
- Closures: Object extension
and for historic interest:
- closures (rfc)
- removal-of-this (rfc:closures)
One thing that Gordon missed is re-binding of $this
. While what he described is the default behaviour, it is possible to re-bind it.
Example
class A {
public $foo = 'foo';
private $bar = 'bar';
public function getClosure() {
return function ($prop) {
return $this->$prop;
};
}
}
class B {
public $foo = 'baz';
private $bar = 'bazinga';
}
$a = new A();
$f = $a->getClosure();
var_dump($f('foo')); // prints foo
var_dump($f('bar')); // works! prints bar
$b = new B();
$f2 = $f->bindTo($b);
var_dump($f2('foo')); // prints baz
var_dump($f2('bar')); // error
$f3 = $f->bindTo($b, $b);
var_dump($f3('bar')); // works! prints bazinga
The closures bindTo
instance method (alternatively use the static Closure::bind
) will return a new closure with $this
re-bound to the value given. The scope is set by passing the second argument, this will determine visibility of private and protected members, when accessed from within the closure.
- PHP: Closure
- Blog post: Closure Object Binding in PHP 5.4
Building on @Gordon's answer it is posible to mimic some hacky aspects of closure-$this in PHP 5.3.
<?php
class A
{
public $value = 12;
public function getClosure()
{
$self = $this;
return function() use($self)
{
return $self->value;
};
}
}
$a = new A;
$fn = $a->getClosure();
echo $fn(); // 12
Just building on the other answers here, I think this example will demonstrate what is possible PHP 5.4+:
<?php
class Mailer {
public $publicVar = 'Goodbye ';
protected $protectedVar = 'Josie ';
private $privateVar = 'I love CORNFLAKES';
public function mail($t, $closure) {
var_dump($t, $closure());
}
}
class SendsMail {
public $publicVar = 'Hello ';
protected $protectedVar = 'Martin ';
private $privateVar = 'I love EGGS';
public function aMailingMethod() {
$mailer = new Mailer();
$mailer->mail(
$this->publicVar . $this->protectedVar . $this->privateVar,
function() {
return $this->publicVar . $this->protectedVar . $this->privateVar;
}
);
}
}
$sendsMail = new SendsMail();
$sendsMail->aMailingMethod();
// prints:
// string(24) "Hello Martin I love EGGS"
// string(24) "Hello Martin I love EGGS"
see: https://eval.in/private/3183e0949dd2db