本文主要和大家分享PHP中Closure類詳解,PHP Closure 類是用於代表匿名函數的類,匿名函數(在 PHP 5.3 中被引入)會產生這個類型的對象,Closure類摘要如下:
Closure { __construct ( void ) public static Closure bind (Closure $closure , object $newthis [, mixed $newscope = 'static' ]) public Closure bindTo (object $newthis [, mixed $newscope = 'static' ])}
方法說明:
Closure::__construct — 用于禁止執行個體化的建構函式
Closure::bind — 複製一個閉包,綁定指定的$this對象和類範圍。
Closure::bindTo — 複製當前閉包對象,綁定指定的$this對象和類範圍。
除了此處列出的方法,還有一個 __invoke 方法。這是為了與其他實現了 __invoke()魔術方法 的對象保持一致性,但調用閉包對象的過程與它無關。
下面將介紹Closure::bind和Closure::bindTo。
Closure::bind是Closure::bindTo的靜態版本,其說明如下:
public static Closure bind (Closure $closure , object $newthis [, mixed $newscope = 'static' ])
closure表示需要綁定的閉包對象。
newthis表示需要綁定到閉包對象的對象,或者NULL建立未綁定的閉包。
newscope表示想要綁定給閉包的類範圍,可以傳入類名或類的樣本,預設值是 'static', 表示不改變。
該方法成功時返回一個新的 Closure 對象,失敗時返回FALSE。
例子說明:
<?php/** * 複製一個閉包,綁定指定的$this對象和類範圍。 * * @author 瘋狂老司機 */class Animal { private static $cat = "cat"; private $dog = "dog"; public $pig = "pig";}/* * 擷取Animal類靜態私人成員屬性 */$cat = static function() { return Animal::$cat;};/* * 擷取Animal執行個體私人成員屬性 */$dog = function() { return $this->dog;};/* * 擷取Animal執行個體公有成員屬性 */$pig = function() { return $this->pig;};$bindCat = Closure::bind($cat, null, new Animal());// 給閉包綁定了Animal執行個體的範圍,但未給閉包綁定$this對象$bindDog = Closure::bind($dog, new Animal(), 'Animal');// 給閉包綁定了Animal類的範圍,同時將Animal執行個體對象作為$this對象綁定給閉包$bindPig = Closure::bind($pig, new Animal());// 將Animal執行個體對象作為$this對象綁定給閉包,保留閉包原有範圍echo $bindCat(),'<br>';// 根據綁定規則,允許閉包通過範圍限定操作符擷取Animal類靜態私人成員屬性echo $bindDog(),'<br>';// 根據綁定規則,允許閉包通過綁定的$this對象(Animal執行個體對象)擷取Animal執行個體私人成員屬性echo $bindPig(),'<br>';// 根據綁定規則,允許閉包通過綁定的$this對象擷取Animal執行個體公有成員屬性?>
輸出:
cat
dog
pig
Closure::bindTo — 複製當前閉包對象,綁定指定的$this對象和類範圍,其說明如下:
public Closure Closure::bindTo (object $newthis [, mixed $newscope = 'static' ])
newthis表示綁定給閉包對象的一個對象,或者NULL來取消綁定。
newscope表示關聯到閉包對象的類範圍,可以傳入類名或類的樣本,預設值是 'static', 表示不改變。
該方法建立並返回一個閉包對象,它與當前對象綁定了同樣變數,但可以綁定不同的對象,也可以綁定新的類範圍。綁定的對象決定了返回的閉包對象中的$this的取值,類範圍決定返回的閉包對象能夠調用哪些方法,也就是說,此時$this可以調用的方法,與newscope類範圍相同。
例子1:
<?phpfunction __autoload($class) { require_once "$class.php";}$template = new Template;$template->render(new Article, 'tpl.php');?>
Template.php 模板類
<?php/** * 模板類,用於渲染輸出 * * @author 瘋狂老司機 */class Template{ /** * 渲染方法 * * @access public * @param obj 資訊類 * @param string 模板檔案名稱 */ public function render($context, $tpl){ $closure = function($tpl){ ob_start(); include $tpl; return ob_end_flush(); }; $closure = $closure->bindTo($context, $context); $closure($tpl); }}
Article.php 資訊類
<?php/** * 文章資訊類 * * @author 瘋狂老司機 */class Article{ private $title = "這是文章標題"; private $content = "這是文章內容";}
tpl.php 模板檔案
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> </head> <body> <h1><?php echo $this->title;?></h1> <p><?php echo $this->content;?></p> </body></html>
運行時確保以上檔案位於同級目錄。
輸出:
這是文章標題
這是文章內容
例子2:
<?php/** * 給類動態添加新方法 * * @author 瘋狂老司機 */trait DynamicTrait { /** * 自動調用類中存在的方法 */ public function __call($name, $args) { if(is_callable($this->$name)){ return call_user_func($this->$name, $args); }else{ throw new \RuntimeException("Method {$name} does not exist"); } } /** * 添加方法 */ public function __set($name, $value) { $this->$name = is_callable($value)? $value->bindTo($this, $this): $value; }}/** * 只帶屬性不帶方法動物類 * * @author 瘋狂老司機 */class Animal { use DynamicTrait; private $dog = 'dog';}$animal = new Animal;// 往動物類執行個體中添加一個方法擷取執行個體的私人屬性$dog$animal->getdog = function() { return $this->dog;};echo $animal->getdog();?>
輸出:
dog
例子3:
<?php/** * 一個基本的購物車,包括一些已經添加的商品和每種商品的數量 * * @author 瘋狂老司機 */class Cart { // 定義商品價格 const PRICE_BUTTER = 1.00; const PRICE_MILK = 3.33; const PRICE_EGGS = 8.88; protected $products = array(); /** * 添加商品和數量 * * @access public * @param string 商品名稱 * @param string 商品數量 */ public function add($item, $quantity) { $this->products[$item] = $quantity; } /** * 擷取單項商品數量 * * @access public * @param string 商品名稱 */ public function getQuantity($item) { return isset($this->products[$item]) ? $this->products[$item] : FALSE; } /** * 擷取總價 * * @access public * @param string 稅率 */ public function getTotal($tax) { $total = 0.00; $callback = function ($quantity, $item) use ($tax, &$total) { $pricePerItem = constant(__CLASS__ . "::PRICE_" . strtoupper($item)); $total += ($pricePerItem * $quantity) * ($tax + 1.0); }; array_walk($this->products, $callback); return round($total, 2);; }}$my_cart = new Cart;// 往購物車裡添加商品及對應數量$my_cart->add('butter', 10);$my_cart->add('milk', 3);$my_cart->add('eggs', 12);// 打出出總價格,其中有 5% 的銷售稅.echo $my_cart->getTotal(0.05);?>
輸出:
132.88
補充說明:閉包可以使用USE關鍵串連外部變數。
總結:合理使用閉包能使代碼更加簡潔和精鍊。
相關推薦:
介紹php中closure使用執行個體
php 中的closure用法執行個體詳解
php 中closure的介紹