ホームページ  >  記事  >  バックエンド開発  >  phpクロージャは匿名関数を作成します

phpクロージャは匿名関数を作成します

怪我咯
怪我咯オリジナル
2017-06-28 11:22:451185ブラウズ

Closureクラス

は、匿名関数を表すために使用されるクラスです。

匿名関数 (PHP 5.3 で導入) は、このタイプのオブジェクトを生成します。以前は、このクラスは実装の詳細とみなされていましたが、現在はこのクラスに依存して何かを行うことができます。 PHP 5.4 以降、
このクラスには、作成後の匿名関数をより詳細に制御できるメソッドが付属しています。

このクラスには 2 つの主要なメソッドがあり、どちらもクロージャをコピーするために使用されます。これらの 2 つの理解しにくいメソッドについては、以下で詳しく説明します。

Closure::bind

public static Closure Closure::bind ( Closure $closure , object $newthis [, mixed $newscope = 'static' ] )

参数说明:
closure
需要绑定的匿名函数。

newthis
需要绑定到匿名函数的对象,或者 NULL 创建未绑定的闭包。

newscope
想要绑定给闭包的类作用域,或者 'static' 表示不改变。如果传入一个对象,则使用这个对象的类型名。 类作用域用来决定在闭包中 $this 对象的 
私有、保护方法 的可见性。 The class scope to which associate the closure is to be associated, or 'static' to keep the 
current one. If an object is given, the type of the object will be used instead. This determines the visibility of 
protected and private methods of the bound object.

上記はこのメソッドの定義です。最初のパラメータは理解しやすいですが、コピーされるクロージャが次のパラメータを含む場合はわかりません。 $this、このオブジェクトはこの $this,这个对象就表示这个
$this,闭包函数里面对这个对象的修改在调用结束之后也会保持一致,比如修改了一个属性;第三个参数就不太好理解了,看官方的说明也是云里雾里的,
默认参数情况下,调用$this->访问object $newthis中的属性函数的时候,会有限制,只能访问public属性的函数,如果想访问protected/private属性,
就要设置为对应的类名/类实例,就要像在类里面一样,要访问那个类的保护/私有属性函数。

例子

<?php
class T {
    private function show()
    {
        echo "我是T里面的私有函数:show\n";
    }

    protected  function who()
    {
        echo "我是T里面的保护函数:who\n";
    }

    public function name()
    {
        echo "我是T里面的公共函数:name\n";
    }
}

$test = new T();

$func = Closure::bind(function(){
    $this->who();
    $this->name();
    $this->show();
}, $test);

$func();

上面的代码会报错Fatal error: Uncaught Error: Call to protected method T::who() from  context 'Closure'。 加上bind第三个参数为t<a href="http://www.php.cn/wiki/167.html" target="_blank">::class</a>或者new T(),会正常输出每一个结果。

我是T里面的保护函数:who
我是T里面的公共函数:name
我是T里面的私有函数:show

当然了,闭包也可以传递参数

$test = new StdClass();
var_dump($test);

$func = Closure::bind(function($obj){
    $obj->name = "燕睿涛";
}, null);

$func($test);
var_dump($test);

上面的程序跟匿名函数一样,啥对象也没有依赖,上面的程序会输出:

object(stdClass)#1 (0) {
}
object(stdClass)#1 (1) {
  ["name"]=>
  string(9) "燕睿涛"
}

另外还有个特别要说明的例子

<?php
class T {
    private function show()
    {
        echo "我是T里面的私有函数:show\n";
    }

    protected  function who()
    {
        echo "我是T里面的保护函数:who\n";
    }

    public function name()
    {
        echo "我是T里面的公共函数:name\n";
    }
}

$func = Closure::bind(function ($obj) {
    $obj->show();
}, null);

$test = new T();

$func($test);

上面的情况会输出什么呢,没错,会报错,提示访问不了私有属性show,这个时候,加上第三个参数就可以了,看了第三个参数不光影响$this的作用域,
也可以影响参数的作用域。

Closure::bindTo

bindTobind功能类似,这里只是另外一种形式,都是复制当前闭包对象,绑定指定的$this对象和类作用域。,参数比bind少了第一个,
后面两个一样,当然还有一个区别就是bindTo不是静态方法,是闭包才会存在的一个属性方法。

例子

<?php
class T {
    private function show()
    {
        echo "我是T里面的私有函数:show\n";
    }

    protected  function who()
    {
        echo "我是T里面的保护函数:who\n";
    }

    public function name()
    {
        echo "我是T里面的公共函数:name\n";
    }
}

$func = function () {
    $this->show();
    $this->who();
    $this->name();
};

$funcNew = $func->bindTo(new T(), T::class);

$funcNew();

上面函数的输出和bind的类似

我是T里面的私有函数:show
我是T里面的保护函数:who
我是T里面的公共函数:name

一个trick

这个函数是在看composer生成的自动加载源码的时候碰到的,在composer中用的比较特别,下面是截取部分composer中的代码

// 文件autoload_real.php
call_user_func(\Composer\Autoload\ComposerStaticInit898ad46cb49e20577400c63254121bac::getInitializer($loader));

// 文件autoload_static.php
public static function getInitializer(ClassLoader $loader)
{
    return \Closure::bind(function () use ($loader) {
        $loader->prefixLengthsPsr4 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixLengthsPsr4;
        $loader->prefixDirsPsr4 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixDirsPsr4;
        $loader->prefixesPsr0 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixesPsr0;
        $loader->classMap = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$classMap;

    }, null, ClassLoader::class);
}

上面的代码比较奇特,在call_user_func中,第一感觉是传错参数了,其实不然,这里调用了一个函数,这个函数会返回一个Closure对象,
也就是一个匿名函数,最终传入的参数还是一个callable类型。再看看这个返回的闭包,里面使用了use$this を表します。属性の変更など、呼び出しが完了した後もこのオブジェクトに対する変更は一貫しています。パラメータは理解するのが簡単ではありません。公式の説明も不明瞭です。
デフォルトのパラメータでは、$this-> を呼び出して object $newthis にアクセスします。 code> にアクセスするには、<code>public 属性を持つ関数のみにアクセスできます。protected/private 属性にアクセスしたい場合は、

を対応するクラス名に設定する必要があります。 /class インスタンスは、クラスと同様に、そのクラスの protected/private 属性関数にアクセスする必要があります。

call_user_func(\Composer\Autoload\ComposerStaticInit898ad46cb49e20577400c63254121bac::getInitializer(), $loader);

public static function getInitializer()
{
    return \Closure::bind(function ($loader) {
        $loader->prefixLengthsPsr4 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixLengthsPsr4;
        $loader->prefixDirsPsr4 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixDirsPsr4;
        $loader->prefixesPsr0 = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$prefixesPsr0;
        $loader->classMap = ComposerStaticInit25885cdf386fdaafc0bce14bb5a7d06e::$classMap;

    }, null, ClassLoader::class);
}
上記のコードは、エラー 致命的なエラー: キャッチされないエラー: コンテキスト 'Closure' から保護されたメソッド T::who() を呼び出します を報告します。 バインドの 3 番目のパラメータを t<a href="http://www.php.cn/wiki/167.html" target="_blank">::class🎜</a> または として追加します。 new T() は通常どおり各結果を出力します。 🎜rrreee🎜もちろん、クロージャはパラメータを渡すこともできます🎜rrreee🎜上記のプログラムは匿名関数と同じであり、どのオブジェクトにも依存しません。上記のプログラムは出力します: 🎜rrreee🎜以下を行う必要がある特別な例もあります。説明します🎜rrreee🎜 上記の状況では何が出力されますか? はい、プライベート属性 show にアクセスできないことを示すエラーが報告されます。この時点では、3 番目のパラメーターを追加するだけです。 3 番目のパラメータを読み取ると、$this に影響するだけでなく、🎜 パラメータのスコープにも影響を与える可能性があります。 🎜🎜Closure::bindTo🎜🎜🎜bindTobind も同様に機能します。ここでは別の形式を示します。両方の <code> は現在のクロージャ オブジェクトをコピーし、指定された $this オブジェクトとクラス スコープをバインドします。 の場合、最初のパラメータは bind より小さく、後の 2 つは同じです。もちろん、もう 1 つの違いがあります。bindTo は静的メソッドではありません。ただし、プロパティメソッドは存在します。 🎜

rrreee🎜上記の関数の出力は、bind の出力と似ています🎜rrreee🎜トリック🎜🎜この関数は、composer
🎜ソースコードを自動的にロードするときに発生しました。これは、composer で特別に使用されます。以下は、 Composer のコード🎜rrreee 🎜 call_user_func では、最初の印象では、間違ったパラメータが渡されていますが、実際にはそうではありません。この関数は Closure オブジェクトを返します。🎜これは匿名関数であり、渡される最後のパラメータは callable 型のままです。返されたクロージャをもう一度見てください。 use がクロージャと外部変数を接続するブリッジとして使用されています。 🎜なぜここで通常のパラメータを渡すことができるかというと、PHP5ではオブジェクトの仮パラメータと実パラメータが同じオブジェクトを指しており、関数内でオブジェクトに加えた変更がオブジェクト外に反映されるためです。 🎜🎜ということで、上記の通りで大丈夫です、別の方法もあります🎜rree

以上がphpクロージャは匿名関数を作成しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。