1).闭包和匿名函数在PHP5.3中被引入。
2).闭包是指在建立时封装函数周围状态的函数,即便闭包所在的环境不存在了,闭包封装的状态依然存在,这一点和Javascript的闭包特性很类似。
3).匿名函数就是没有名称的函数,匿名函数能够赋值给变量,还能够像其余任何PHP对象同样传递。能够将匿名函数和闭包视做相同的概念。
4).须要注意的是闭包使用的语法和普通函数相同,可是他实际上是假装成函数的对象,是Closure类的实例。闭包和字符串或整数同样,是一等值类型。php
$closure = function ($name) {
return sprintf('hello %s', $name);
};
echo $closure('Josh');复制代码
咱们之因此能够调用$closure变量,是由于这个变量的值是一个闭包,并且闭包对象实现了__invoke()
魔术方法,只要后面跟着()
,PHP就会查找__invoke()
方法。这里简单解释下这个魔术方法:html
class testClass {
public function __invoke {
print "hello world";
}
}
$n = new testClass;
$n();复制代码
PHP自从5.3版以来就新增了一个叫作__invoke()
的魔术方法,使用该方法就能够在建立实例后,直接调用对象。git
咱们一般把PHP闭包当作函数和方法的回调使用。不少PHP函数都会用到回调函数,例如array_map()
和preg_replace_callback()
。github
$numbersPlusOne = array_map(function($number) {
return $number + 1;
}, [1, 2, 3]);复制代码
1).注意PHP闭包不会真的像JS同样自动封装应用的状态,在PHP中必须调用闭包对象的bindTo方法或者使用use关键字,把状态附加到PHP闭包上。来看一个例子web
function enclosePerson($name) {
return function ($doCommand) use ($name) {
return sprintf('%s , %s', $name, $doCommand);
};
}
//把字符串“Clay”封装在闭包中
$clay = enclosePerson('Clay');
//传入参数,调用闭包
echo $clay('get me sweat tea!'); // Clay, get me sweat tea!复制代码
在这个例子中,函数enclosePerson()
有一个$name
参数,这个函数返回一个闭包对象,这个闭包封装了$name
参数,即使返回的对象跳出了enclosePerson()
函数的做用域,它也会记住$name
参数的值,由于$name
变量仍然在闭包中。
2).使用use关键字能够把多个关键字传入闭包,此时要想像PHP函数或方法的参数同样,使用逗号分割多个参数。
3).PHP闭包仍然是对象,可使用$this关键字获取闭包的内部状态。闭包的默认状态里面有一个__invoke()
魔术方法和bindTo()
方法。
4).bindTo()
方法为闭包增长了一些有趣的东西。咱们可使用这个方法把Closure对象内部状态绑定到其余对象上。bindTo()
方法的第二个参数能够指定绑定闭包的那个对象所属的PHP类,这样咱们就能够访问这个类的受保护和私有的成员变量。看下面的代码示例:json
class App {
protected $route = array();
protected $responseStatus = '200 OK';
protected $responseContentType = 'text/html';
protected $responseBody = 'Hello world';
public function addRoute($routePath, $routeCallback) {
$this->routes[$routePath] = $routeCallback->bindTo($this, __CLASS__);
}
public function dispatch($currentPath) {
foreach($this->routes as $routePath => $callback) {
if ($routePath === $currentPath) {
$callback();
}
}
header('HTTP/1.1' . $this->responseStatus);
header('Content-type: ' . $this->responseContentType);
header('Content-length: ' . mb_strlen($this->responseBody));
echo $this->responseBody;
}
}复制代码
咱们把路由回调绑定到了当前的App实例上,这样就能够在回调函数中处理App实例的状态了。闭包
$app = new App();
$app->addRoute('/users/xiaoxiao', function () {
$this->responseContentType = 'application/json;charset=utf8';
$this->responseBody = '{"name" : "xiaoxiao"}';
});
$app->dispatch('/users/xiaoxiao');复制代码
PHP专题系列目录地址:github.com/xx19941215/…
PHP专题系列预计写二十篇左右,主要总结咱们平常PHP开发中容易忽略的基础知识和现代PHP开发中关于规范、部署、优化的一些实战性建议,同时还有对Javascript语言特色的深刻研究。app