web-dev-qa-db-ja.com

PHP 5.4-'closure $ this support'

PHP 5.4で計画されている新しい機能は次のとおりです。特性、配列の参照解除、JsonSerializableインターフェイス、および 'closure $this support '

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

他のものはすぐに明らかになるか(JsonSerialiable、配列参照解除)、または詳細(特性)を調べましたが、 'closure $ this support'が何であるかわかりません。私はそれのためにグーグルで失敗したか、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;
                     }
                 };

重要性は(この例が些細なものであっても)過去にクロージャが構築されると、バインドされた「use」変数が固定されることです。 'closure $ this support'を使用すると、彼らはあなたが台無しにできるメンバーのようになります。

この音は正しい、および/または近い、および/または合理的ですか?この「クロージャー$ thisサポート」の意味を誰もが知っていますか?

68
jon_darkstar

これはすでにPHP 5.3で計画されていましたが、

For PHP 5.3 $このクロージャのサポートは、コンセンサスに健全な方法で実装することができなかったため削除されました。 PHPバージョン。

実際、オブジェクトインスタンスを参照できることを意味します( 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

議論については、PHP Wiki

そして歴史的な興味のために:

74
Gordon

ゴードンが見逃したことの1つは、$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インスタンスメソッド(代わりに静的Closure::bind)は、$this指定された値に再バインドします。スコープは、2番目の引数を渡すことで設定されます。これにより、クロージャー内からアクセスしたときに、プライベートメンバーと保護メンバーの可視性が決まります。

53
igorw

@Gordonの答えに基づいて、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
22
Xeoncross

ここで他の答えに基づいて、この例は可能なことを示していると思います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