PHP 5.4-'关闭$ this支持'


68

我看到PHP 5.4的新计划功能是:特征,数组解引用,JsonSerializable接口和称为“ closure $this support”的东西。

http://en.wikipedia.org/wiki/Php#Release_history

尽管其他人要么立即清楚(JsonSerialiable,数组取消引用),要么我查看了具体细节(特征),但我不确定“关闭$ this支持”是什么。我一直在搜寻它或在php.net上找到关于它的任何内容均未成功

有人知道这应该是什么吗?

如果我不得不猜测,那就意味着这样:

$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;
                     }
                 };

重要性(即使该示例是微不足道的)是,在过去,一旦构造了闭包,绑定的“使用”变量就被固定了。有了“ closure $ this support”,他们更像是您可以弄乱的成员。

这听起来是否正确和/或接近和/或合理?有人知道“关闭此支持”意味着什么吗?


FWIW,5.4尚未成为PHP主干的正式名称-它在内部仍被称为“ 5.3.99”,并且关于它是否真的是5.4(相对于6.0,是否与5.4大不相关)存在一些争议Unicode重写“ 6.0”分支)。
查尔斯

啊,很高兴知道。感谢您修复标签
jon_darkstar 2011年

Answers:


74

这已经为PHP 5.3计划了,但是

对于PHP 5.3,已删除对Closures的支持,因为无法达成共识,如何以理智的方式实现它。该RFC描述了在下一个PHP版本中可以采用的可能方法。

这确实意味着您可以引用对象实例(实时演示

<?php
class A {
  private $value = 1;
  public function getClosure() 
  {
    return function() { return $this->value; };
  }
}

$a = new A;
$fn = $a->getClosure();
echo $fn(); // 1

有关讨论,请参见PHP Wiki。

并且出于历史利益:


噢,我的方向完全错误。您的意思是“ $ this”是Foo正确的实例吗?我认为“ $ this”是闭包本身。将use仍然是必要的?
jon_darkstar 2011年

3
@jon不,use甚至无法使用。迄今为止,您不能在任何PHP版本中将$ this用作词法变量。我使用Wiki中的示例进行了更新,并提供了指向键盘的链接,其中显示了当前PHP主干的结果。
Gordon

1
谢谢,这太好了。顺便说一句-public $closure什么也没做,只会分散您的注意力,您也可以很好地证明这一点
jon_darkstar 2011年

1
@Gordon-我认为乔恩use在一般情况下是指–不是特定于$this。AFAIK,use仍然需要访问局部变量。我很期待放弃这个use ($self)窍门。:)
David Harkness

1
@Bracketworks我不确定100%,但是更多参与该决定的人告诉我,他们认为这是A。–
Gordon

53

戈登错过的一件事是重新绑定$this。虽然他描述的是默认行为,但可以重新绑定它。

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

闭包bindTo实例方法(或者使用static Closure::bind)将返回一个新的闭包,并$this重新绑定到给定的值。范围是通过传递第二个参数来设置的,当从闭包内部进行访问时,这将确定私有成员和受保护成员的可见性。


6
+1用于描述bindTo()功能,这是非常重要的功能。
Darragh Enright 2012年

22

以@Gordon的答案为基础,有可能模仿PHP 5.3中闭包的某些棘手方面-$ this。

<?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

10
是的,但是一个显着的区别是您不能$self从闭包内部访问任何私有或受保护的属性或方法。
jgivoni 2012年

3
+1哈哈,一年后找到了这个答案,它解决了我的问题。;)
Xeoncross

@jgivoni是什么意思,无法在PHP 5.3中访问私有或受保护的变量?
Shiro

2
@Shiro,是的。5.3的此解决方法仅适用于公共属性。
jgivoni 2014年

@Pacerier,我不知道在PHP 5.3的闭包中访问非公共属性的任何解决方法。最好的建议是升级到5.4或更高版本。
jgivoni 2014年

2

只是在这里基于其他答案的基础上,我认为这个示例将演示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"

参见:https : //eval.in/private/3183e0949dd2db

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.