1. 什麼是閉包閉包個人理解就是一個能提供外部存取函數內局部變數的匿名函數
2. 為什麼要用閉包閉包的定義已經說明了,我們想在外部存取函數內的局部變數,為了達到這個目的,我們需要使用閉包。
3. 閉包的使用
(0) 使用前提PHP version >= 5.3.0
(1) 匿名函數的使用
我們先實現一個類似js的相加操作
$add = function($type = 'number'){ if($type == 'number'){ return function($a,$b){ return $a+$b; } }if($type == 'string'){ return function($a,$b){ return $a.$b; } }}$typeadd = $add('number');$typeadd(1,23); // 24$typeadd = $add('string');$typeadd(1,23); // 123
(2) Closure的執行個體化對象
所有的匿名函數都是Closure 閉包的執行個體化對象
而Closure提供了兩個非常有用的方法 bindTo 和bind,使用者將其他的對象狀態綁定到匿名函數上,使得匿名函數能訪問其他對象的方法和屬性。
A. 首先看bindTo的例子【入門栗子】
class A{private $a1 = 1;protected $a2 = 2;public $a3 = 3;}$closure1 = function($member){return $this->$member;};$a = new A();$aa1 = $closure1->bindTo($a);//echo $aa1('a1'); //私人成員不能訪問//echo $aa1('a2'); //保護成員不能訪問 echo $aa1('a3');$aa2 = $closure1->bindTo($a,'A');$aa3 = $closure1->bindTo($a,$a);echo $aa2('a1');echo $aa3('a2');
可以很直觀的看出, bindTo 有兩個參數,
第一個參數是要綁定的對象(對象),
第二個參數是綁定對象限定的範圍(對象 或者 類名)
bindTo($a) //只能訪問A的公有方法和屬性
bindTo($a,'A')
bindTo($a,$a) //可以訪問A的所有方法和屬性
如果第二個參數是第一個參數的父類,則限定只能訪問父類的所有方法和屬性
以及子類公有方法和屬性
【複雜例子】
Laravel 路由
class App {private $routes = [];private $response = '';public function addRoute($path,$callback){ $this->routes[$path] = $callback->bindTo($this,__CLASS__);}public function dispatch($currentPath){ foreach($this->routes as $route => $callback){ if($route === $currentPath){ $callback(); } } echo $this->response;}}$app = new App();$app->addRoute('a/b',function(){$this->response = 'this is a/b';});$app->addRoute('c/d',function(){$this->response = 'this is c/d';});$app->dispatch('a/b');
B. bind是bindTo的靜態版本使用方式
(1)類的靜態成員變數或方法
Closure::bind(closureFunc,null,className);
(2)類的普通成員變數或方法
Closure::bind(closureFunc,new ClassName(), className);
(3) 最常用的 use
最常用的保留狀態或者說訪問函數局部變數的是 使用use關鍵字
function a($name){ $i = 0; return function() use($name, &$i){ $i++; echo $name.':'; echo $i; };}$a1 = a('zhangsan');$a2 = a('lisi');$a1(); //zhangsan:1 $a1(); //zhangsan:2 name 和 i 的狀態被保留$a2(); //lisi:1 name 和 i 的狀態被重新初始化
各自的狀態互不影響,但各自變數狀態卻始終保留,這就是use