PHP基于Closure類創(chuàng)建匿名函數(shù)的方法詳解
本文實例講述了PHP基于Closure類創(chuàng)建匿名函數(shù)的方法。分享給大家供大家參考,具體如下:
Closure 類
用于代表匿名函數(shù)的類。
匿名函數(shù)(在 PHP 5.3 中被引入)會產(chǎn)生這個類型的對象。在過去,這個類被認(rèn)為是一個實現(xiàn)細(xì)節(jié),但現(xiàn)在可以依賴它做一些事情。自 PHP 5.4 起,這個類帶有一些方法,允許在匿名函數(shù)創(chuàng)建后對其進(jìn)行更多的控制。
這個類不能實例化,里面主要有兩個方法,都用來復(fù)制閉包,一個靜態(tài)一個動態(tài),下面分別詳細(xì)講解下這兩個不好理解的方法。
Closure::bind
public static Closure Closure::bind ( Closure $closure , object $newthis [, mixed $newscope = 'static' ] )
參數(shù)說明:
closure
需要綁定的匿名函數(shù)。
newthis
需要綁定到匿名函數(shù)的對象,或者 NULL 創(chuàng)建未綁定的閉包。
newscope
想要綁定給閉包的類作用域,或者 'static' 表示不改變。如果傳入一個對象,則使用這個對象的類型名。 類作用域用來決定在閉包中 $this 對象的 私有、保護(hù)方法 的可見性。
The class scope to which associate the closure is to be associated, or 'static' to keep the current one. If an object is given, the type of the object will be used instead. This determines the visibility of protected and private methods of the bound object.
上面是該方法的定義,第一個參數(shù)很好理解,就是一個閉包函數(shù);第二個參數(shù)就不太好理解,如果要復(fù)制的閉包中包含$this,這個對象就表示這個$this,閉包函數(shù)里面對這個對象的修改在調(diào)用結(jié)束之后也會保持一致,比如修改了一個屬性;第三個參數(shù)就不太好理解了,看官方的說明也是云里霧里的,默認(rèn)參數(shù)情況下,調(diào)用$this->訪問object $newthis中的屬性函數(shù)的時候,會有限制,只能訪問public屬性的函數(shù),如果想訪問protected/private屬性,就要設(shè)置為對應(yīng)的類名/類實例,就要像在類里面一樣,要訪問那個類的保護(hù)/私有屬性函數(shù)。
例子
<?php class T { private function show() { echo "我是T里面的私有函數(shù):show\n"; } protected function who() { echo "我是T里面的保護(hù)函數(shù):who\n"; } public function name() { echo "我是T里面的公共函數(shù):name\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第三個參數(shù)為t::class或者new T(),會正常輸出每一個結(jié)果。
我是T里面的保護(hù)函數(shù):who 我是T里面的公共函數(shù):name 我是T里面的私有函數(shù):show
當(dāng)然了,閉包也可以傳遞參數(shù)
$test = new StdClass(); var_dump($test); $func = Closure::bind(function($obj){ $obj->name = "燕睿濤"; }, null); $func($test); var_dump($test);
上面的程序跟匿名函數(shù)一樣,啥對象也沒有依賴,上面的程序會輸出:
object(stdClass)#1 (0) { } object(stdClass)#1 (1) { ["name"]=> string(9) "燕睿濤" }
另外還有個特別要說明的例子
<?php class T { private function show() { echo "我是T里面的私有函數(shù):show\n"; } protected function who() { echo "我是T里面的保護(hù)函數(shù):who\n"; } public function name() { echo "我是T里面的公共函數(shù):name\n"; } } $func = Closure::bind(function ($obj) { $obj->show(); }, null); $test = new T(); $func($test);
上面的情況會輸出什么呢,沒錯,會報錯,提示訪問不了私有屬性show,這個時候,加上第三個參數(shù)就可以了,看了第三個參數(shù)不光影響$this的作用域,也可以影響參數(shù)的作用域。
Closure::bindTo
bindTo和bind功能類似,這里只是另外一種形式,都是復(fù)制當(dāng)前閉包對象,綁定指定的$this對象和類作用域。,參數(shù)比bind少了第一個,后面兩個一樣,當(dāng)然還有一個區(qū)別就是bindTo不是靜態(tài)方法,是閉包才會存在的一個屬性方法。
例子
<?php class T { private function show() { echo "我是T里面的私有函數(shù):show\n"; } protected function who() { echo "我是T里面的保護(hù)函數(shù):who\n"; } public function name() { echo "我是T里面的公共函數(shù):name\n"; } } $func = function () { $this->show(); $this->who(); $this->name(); }; $funcNew = $func->bindTo(new T(), T::class); $funcNew();
上面函數(shù)的輸出和bind的類似
我是T里面的私有函數(shù):show 我是T里面的保護(hù)函數(shù):who 我是T里面的公共函數(shù):name
一個trick
這個函數(shù)是在看composer生成的自動加載源碼的時候碰到的,在composer中用的比較特別,下面是截取部分composer中的代碼
// 文件autoload_real.php call_user_func(\Composer\Autoload\ComposerStaticInit898ad46cb49e20577400c63254121bac::getInitializer($loader)); // 文件autoload_static.php public 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中,第一感覺是傳錯參數(shù)了,其實不然,這里調(diào)用了一個函數(shù),這個函數(shù)會返回一個Closure對象,也就是一個匿名函數(shù),最終傳入的參數(shù)還是一個callable類型。再看看這個返回的閉包,里面使用了use,這是連接閉包和外部變量的橋梁。
至于這里為什么普通傳參數(shù)就可以,是因為php5里面,對象形參和實參數(shù)指向相同的對象,函數(shù)里面對對象的修改會反映到對象外面。
所以,上面這么做是沒問題的,還有另外一種形式也可以
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); }
更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《php常用函數(shù)與技巧總結(jié)》、《php字符串(string)用法總結(jié)》、《PHP數(shù)組(Array)操作技巧大全》、《PHP數(shù)據(jù)結(jié)構(gòu)與算法教程》及《php程序設(shè)計算法總結(jié)》
希望本文所述對大家PHP程序設(shè)計有所幫助。
- PHP回調(diào)函數(shù)與匿名函數(shù)實例詳解
- PHP 的異常處理、錯誤的拋出及回調(diào)函數(shù)等面向?qū)ο蟮腻e誤處理方法
- PHP將回調(diào)函數(shù)作用到給定數(shù)組單元的方法
- PHP中call_user_func_array回調(diào)函數(shù)的用法示例
- PHP回調(diào)函數(shù)概念與用法實例分析
- php的閉包(Closure)匿名函數(shù)詳解
- 詳解PHP匿名函數(shù)與注意事項
- PHP匿名函數(shù)和use子句用法實例
- php的閉包(Closure)匿名函數(shù)初探
- PHP回調(diào)函數(shù)及匿名函數(shù)概念與用法詳解
相關(guān)文章
PHP實現(xiàn)二叉樹的深度優(yōu)先與廣度優(yōu)先遍歷方法
這篇文章主要介紹了PHP實現(xiàn)二叉樹的深度優(yōu)先與廣度優(yōu)先遍歷方法,涉及php針對二叉樹進(jìn)行遍歷的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-09-09PHP連接Access數(shù)據(jù)庫的方法小結(jié)
有時候我們在開發(fā)一些小程序或簡單功能的管理系統(tǒng),又沒有mysql數(shù)據(jù)庫的情況下,就可以使用access了,這里介紹下鏈接方法2013-06-06PHP實現(xiàn)支持GET,POST,Multipart/form-data的HTTP請求類
這篇文章主要介紹了PHP實現(xiàn)支持GET,POST,Multipart/form-data的HTTP請求類,包括了連接與處理方式及相關(guān)的技巧,需要的朋友可以參考下2014-09-09PHP fgetcsv 定義和用法(附windows與linux下兼容問題)
PHP fgetcsv() 函數(shù)從文件指針中讀入一行并解析 CSV 字段。與PHP fgets() 類似,不同的是 PHP fgetcsv() 解析讀入的行并找出 CSV 格式的字段,然后返回一個包含這些字段的數(shù)組2012-05-05php gd2 上傳圖片/文字水印/圖片水印/等比例縮略圖/實現(xiàn)代碼
php gd2 上傳圖片/文字水印/圖片水印/等比例縮略圖/源代碼,需要的朋友可以參考下。2010-05-05