PHP 5.4 - 'closure $this support'

2019-01-06 11:32发布

问题:

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?

回答1:

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)


回答2:

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


回答3:

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


回答4:

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



标签: php closures