匿名函数(在 PHP 5.3 中被引入)会产生这个类型的工具。在过去, 这个类被认为是一个实现细节, 但现在可以依赖它做一些事情。自 PHP 5.4 起,
这个类带有一些方法, 许可在匿名函数创建后对其进行更多的掌握。
这个类不能实例化, 里面紧张有两个方法, 都用来复制闭包, 一个静态一个动态, 下面分别详细讲解下这两个不好理解的方法
Closure::bindpublic static Closure Closure::bind ( Closure $closure , object $newthis [, mixed $newscope = 'static' ] )
参数解释:
closure 须要绑定的匿名函数。
newthis 须要绑定到匿名函数的工具, 或者 NULL 创建未绑定的闭包。
newscope 想要绑定给闭包的类浸染域, 或者 'static' 表示不改变。如果传入一个工具, 则利用这个工具的类型名。
类浸染域用来决定在闭包中 $this 工具的私有、保护方法 的可见性。
上面是该方法的定义, 第一个参数很好理解, 便是一个闭包函数;
第二个参数就不太好理解, 如果要复制的闭包中包含$this, 这个工具就表示这个$this, 闭包函数里面对这个工具的修正在调用结束之后也会保持同等,
比如修正了一个属性;
第三个参数就不太好理解了, 看官方的解释也是云里雾里的,
默认参数情形下, 调用$this->访问object $newthis中的属性函数的时候, 会有限定, 只能访问public属性的函数,
如果想访问protected/private属性, 就要设置为对应的类名/类实例, 就要像在类里面一样, 要访问那个类的保护/私有属性函数。
例子
<?phpclass T { private function show() { echo "我是T里面的私有函数:show\r\n"; } protected function who() { echo "我是T里面的保护函数:who\r\n"; } public function name() { echo "我是T里面的公共函数:name\r\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::class或者new T(),会正常输出每一个结果。
<?phpclass T { private function show() { echo "我是T里面的私有函数:show\r\n"; } protected function who() { echo "我是T里面的保护函数:who\r\n"; } public function name() { echo "我是T里面的公共函数:name\r\n"; }}$test = new T();$func = Closure::bind(function(){$this->who();$this->name();$this->show();}, $test, new T());$func();?>/输出结果:我是T里面的保护函数:who 我是T里面的公共函数:name 我是T里面的私有函数:show/
当然了, 闭包也可以通报参数
$test = new StdClass();var_dump($test);echo "<br>";$func = Closure::bind(function($obj){ $obj->name = "燕睿涛";}, null);$func($test);var_dump($test);/object(stdClass)#1 (0) { }object(stdClass)#1 (1) { ["name"]=> string(9) "燕睿涛" }/
其余还有个特殊要解释的例子
<?phpclass 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, 这个时候, 加上第三个参数就可以了(T::class或者new T()), 看了第三个参数不只影响$this的浸染域,
也可以影响参数的浸染域。
Closure::bindTo
bindTo和bind功能类似, 这里只是其余一种形式, 都是复制当前闭包工具, 绑定指定的$this工具和类浸染域。
参数比bind少了第一个, 后面两个一样, 当然还有一个差异便是bindTo不是静态方法, 是闭包才会存在的一个属性方法。
例子
<?phpclass 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.phpcall_user_func(\Composer\Autoload\ComposerStaticInit898ad46cb49e20577400c63254121bac::getInitializer($loader));// 文件autoload_static.phppublic 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, 这是连接闭包和外部变量的桥梁。
至于这里为什么普通传参数就可以, 是由于php5里面, 工具形参和实参数指向相同的工具, 函数里面对工具的修正会反响到工具表面。
以是, 上面这么做是没问题的, 还有其余一种形式也可以
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);}