其实学习一个新的概念,除了知道怎么使用,更多的我是想知道它的使用场景。应用场景才是设计的根源。而对于PHP闭包的讲解,大多都是讲解的例子,但是只知道怎么用,还是不知道用在什么时候。这种情况你是不能灵活使用这个知识点的。
- 以下总结来自于上面推荐文章的总结,但是我觉得是有道理的
1.面向对象变成语言代码的复用主要采用继承来实现,而函数的复用,就是通过闭包来实现。这就是闭包的设计初衷。
2.闭包可以在函数里面访问指定域上午变量,在PHP里使用use关键字来实现。
3.php会自动把闭包函数转换成内置类 Closure 的对象实例,依赖 Closure 的对象实例又给闭包函数添加了更多的能力。
4.Closure::bind 复制一个闭包
,绑定指定 this 对象和类作用域。
5.Closure::bindTo 复制当前闭包对象
,绑定指定的 this对象和类作用域。
- demo.php
class Person
{
public $name = 'test';
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
}
$closure = function () {
return $this->name;
};
$person = new Person();
$bindTo =$closure->bindTo($person);
echo $bindTo(); //test
echo '<br>';
$bind = Closure::bind($closure,$person);
echo($bind());//test
echo '<br>';
$person->setName('new test');
echo $bindTo(); // 'new test'
echo '<br>';
echo($bind()); //'new test'
![](https://img.haomeiwen.com/i2560633/a77a62dba3bb443f.png)
注意
bindTo -- 是将当前闭包 bindTo(绑定到) 对象
bind -- 是将闭包绑定到对象,第一个参数是闭包,第二个参数是对象
Closure::bind Closure::bindTo 都是闭包的特性,而不是对象
bind 的第二个参数和 bindTo的第三个参数newscope
,是关联到匿名函数的类作用域,或者 'static' 保持当前状态。如果是一个对象
,则使用这个对象的类型为心得类作用域。 这会决定绑定的对象的 保护、私有成员 方法的可见性。所以这个对象其实是 class 与 {} 中间的对象名,而不是实例化的那个变量。如果你是在对象中写,可以直接使用 CLASS 表示这个参数。如果不添加这个参数,则不能使用对应的 private、protect 方法或者属性
- Moderm PHP 对比包的讲解
1.理论上闭包和匿名函数是不同的概念。不过,PHP将其视作相同的概念。所以在PHP语言中闭包其实就是匿名函数
2.PHP闭包和匿名函数的句法和普通函数相同,闭包和匿名函数其实是伪装成函数的对象,它们是Closure 类的实例
。闭包和字符串或者整数一样,也是一等值类型。
3.我们之所以能够调用 $closure 变量,使用为这个变量的值是一个闭包,而且闭包对象实现了 _invole() 魔术方法,只要变量后有(),PHP就会查找并调用 _invoke() 方法
- PHP闭包是对象。与人任何其他PHP对象类似,每个闭包实例都可以使用
$this
关键字获取闭包的内部状态。闭包对象的默认状态没什么用,不过有一个 __invoke() 魔术方法和一个bindTo()方法,仅此而已
5.但是,bindTo() 方法为闭包增加了一些有趣的潜力,我们可以使用这个方法把 Closure 对象的内部状态绑定到其他对象上,bindTo(),方法的第二个参数很重要,其作用是指定绑定闭包的那个对象所属的PHP类。因此,闭包可以访问绑定闭包的对象中收保护和私有的成员变量。
6.你会发现,PHP框架经常使用bindTo()方法把路由URL映射到匿名回掉函数上。框架会把匿名函数绑定到应用对象上,这么做,可以在这个匿名函数中使用$this
关键字引用重要的应用对象。
<?php
class App
{
protected $routes = [];
protected $responseBody;
public function addRoute($path, Closure $callback)
{
$this->routes[$path] = $callback->bindTo($this,'App');
}
public function dispatch($currentPath)
{
foreach ($this->routes as $path => $callback) {
if ($path == $currentPath) {
echo $callback();
}
}
}
public function getResponse()
{
return $this->responseBody;
}
}
$app = new App();
$app->addRoute('test', function () {
$this->responseBody = 'test path';
});
$app->addRoute('name', function () {
$this->responseBody = 'name path';
});
$app->dispatch('test');
echo $app->getResponse(); // test path
echo '<br>';
$app->dispatch('name');
echo $app->getResponse(); //test path
当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
也就是只要一个对象的变量(比如以下的$adder) 加上一个()
,其实就会调用__invoke()
方法。
而闭包,就相当于是 Closure 类的__invoke()
方法
-
Closure::call
function call ($newThis, ...$parameters) {}
Closure::call — Binds and calls the closure(绑定一个类,并返回闭包) ----- PHP>=7.0
第一个参数是类的实例化,第二个参数是 __construct() 的参数,return 返回的结果是闭包中返回的结果。
demo 还是上面的那个
$callback = function(){
return $this->responseBody = 'test path';
};
$app = new App();
$app->addRoute('test', $callback);
echo $callback->call($app);
- _invoke() 魔术方法的使用
<?php
class Add {
public $left;
public $right;
public function construct($left = 0, $right = 0) {
$this->left = $left;
$this->right = $right;
}
public function __invoke() {
return $this->left + $this->right;
}
}
$adder = new Add;
$adder->left = 1;
$adder->right = 2;
echo $adder(); // 3
$adder->left = 3;
echo $adder(); // 5
网友评论