PHP Closure建立匿名函數

這個類不能實例化,裏面主要有兩個方法,都用來複制閉包,一個靜態一個動態,下面分別詳細講解下這兩個很差理解的方法。php

Closure::bind

public static Closure Closure::bind ( Closure $closure , object $newthis [, mixed $newscope = 'static' ] ) 參數說明: closure 須要綁定的匿名函數。 newthis 須要綁定到匿名函數的對象,或者 NULL 建立未綁定的閉包。 newscope 想要綁定給閉包的類做用域,或者 'static' 表示不改變。若是傳入一個對象,則使用這個對象的類型名。 類做用域用來決定在閉包中 $this 對象的 私有、保護方法 的可見性。 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.

上面是該方法的定義,第一個參數很好理解,就是一個閉包函數;第二個參數就不太好理解,若是要複製的閉包中包含$this,這個對象就表示這個
$this,閉包函數裏面對這個對象的修改在調用結束以後也會保持一致,好比修改了一個屬性;第三個參數就不太好理解了,看官方的說明也是雲裏霧裏的,
默認參數狀況下,調用$this->訪問object $newthis中的屬性函數的時候,會有限制,只能訪問public屬性的函數,若是想訪問protected/private屬性,
就要設置爲對應的類名/類實例,就要像在類裏面同樣,要訪問那個類的保護/私有屬性函數。sql

例子

<?php class T { private function show() { echo "我是T裏面的私有函數:show\n"; } protected function who() { echo "我是T裏面的保護函數:who\n"; } public function name() { echo "我是T裏面的公共函數: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第三個參數爲t::class或者new T(),會正常輸出每個結果。django

我是T裏面的保護函數:who 我是T裏面的公共函數:name 我是T裏面的私有函數:show

固然了,閉包也能夠傳遞參數閉包

$test = new StdClass(); var_dump($test); $func = Closure::bind(function($obj){ $obj->name = "燕睿濤"; }, null); $func($test); var_dump($test);

上面的程序跟匿名函數同樣,啥對象也沒有依賴,上面的程序會輸出:composer

object(stdClass)#1 (0) { } object(stdClass)#1 (1) { ["name"]=> string(9) "燕睿濤" }

另外還有個特別要說明的例子函數

<?php class T { private function show() { echo "我是T裏面的私有函數:show\n"; } protected function who() { echo "我是T裏面的保護函數:who\n"; } public function name() { echo "我是T裏面的公共函數:name\n"; } } $func = Closure::bind(function ($obj) { $obj->show(); }, null); $test = new T(); $func($test);

上面的狀況會輸出什麼呢,沒錯,會報錯,提示訪問不了私有屬性show,這個時候,加上第三個參數就能夠了,看了第三個參數不光影響$this的做用域,
也能夠影響參數的做用域。學習

Closure::bindTo

bindTobind功能相似,這裏只是另一種形式,都是複製當前閉包對象,綁定指定的$this對象和類做用域。,參數比bind少了第一個,
後面兩個同樣,固然還有一個區別就是bindTo不是靜態方法,是閉包纔會存在的一個屬性方法。ui

例子

<?php class T { private function show() { echo "我是T裏面的私有函數:show\n"; } protected function who() { echo "我是T裏面的保護函數:who\n"; } public function name() { echo "我是T裏面的公共函數:name\n"; } } $func = function () { $this->show(); $this->who(); $this->name(); }; $funcNew = $func->bindTo(new T(), T::class); $funcNew();

上面函數的輸出和bind的相似this

我是T裏面的私有函數:show 我是T裏面的保護函數:who 我是T裏面的公共函數:name

一個trick

這個函數是在看composer生成的自動加載源碼的時候碰到的,在composer中用的比較特別,下面是截取部分composer中的代碼spa

// 文件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中,第一感受是傳錯參數了,其實否則,這裏調用了一個函數,這個函數會返回一個Closure對象,
也就是一個匿名函數,最終傳入的參數仍是一個callable類型。再看看這個返回的閉包,裏面使用了use,這是鏈接閉包和外部變量的橋樑。
至於這裏爲何普通傳參數就能夠,是由於php5裏面,對象形參和實參數指向相同的對象,函數裏面對對象的修改會反映到對象外面。

因此,上面這麼作是沒問題的,還有另一種形式也能夠

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); }

總結

好長時間沒寫blog了,有時候太煩躁,靜不下心來,有時又有沒有找到想寫的東西。仍是得靜下心來,好好作好每一件事,遇事情不要煩躁,心放大,心平氣和的處理每一件事。

寫到最後,突然想起高中的時候,恰好是5.12汶川大地震的時候,咱們在西安,大地震事後還不停的會有餘震,稍微一有餘震,你們就都慌了,一窩蜂的往下衝,我沒記錯的話咱們是在5樓,
直到一次咱們物理老師來上課,這個老師年齡偏大,是市裏面的特級教師(恩,應該沒錯),正好碰到餘震,你們又瘋了似得準備往外跑,這個時候老師說了一句話,讓我至今
難忘,命在骨子裏,這種餘震不必這麼慌擠下去,命硬的怎麼都沒事,確實,這種小余震擠下去可能更容易發生事故,雖然這句話帶了少量的消極,但裏面更多的是心態的平靜、
心比較大、冷靜果斷的體現,這是我要學習的。

該出現的總會出現,不應出現的永遠不會出現,一味的好高騖遠,追求太遠的目標容易致使焦慮,固然要不要妄自菲薄,總之一句話:心平氣和、心放大、切勿患得患失、踏踏實實的作好每一件事,越努力、越幸運,越幸運、越努力。

相關文章
相關標籤/搜索