首頁  >  文章  >  後端開發  >  淺談PHP Closure類及其用法

淺談PHP Closure類及其用法

青灯夜游
青灯夜游轉載
2021-03-05 17:58:414856瀏覽

這篇文章跟大家介紹一下PHP Closure類,以及如何使用Closure建立匿名函數。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

淺談PHP Closure類及其用法

推薦學習:《PHP影片教學

Closure 類別

使用於代表匿名函數的類別。

匿名函數(在 PHP 5.3 中被引入)會產生這個類型的物件。在過去,這個類別被認為是實作細節,但現在可以依賴它做一些事情。自 PHP 5.4 起,
這個類別帶有一些方法,允許在匿名函數創建後對其進行更多的控制。

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

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-&gt ;存取object $newthis中的屬性函數的時候,會有限制,只能存取public屬性的函數,如果想存取protected/private屬性,
就要設定為對應的類別名稱/類別實例,就要像在類別裡面一樣,要存取那個類別的保護/私有屬性函數。

範例

<?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::classnew T(),會正常輸出每一個結果。

我是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);

上面的程式跟匿名函數一樣,啥物件也沒有依賴,上面的程式會輸出:

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不是靜態方法,是閉包才會存在的一個屬性方法。

範例

<?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的類似

我是T里面的私有函数:show
我是T里面的保护函数:who
我是T里面的公共函数:name

#一個trick

#這個函數是在看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中,第一個感覺是傳錯參數了,其實不然,這裡呼叫了一個函數,這個函數會回傳一個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樓,
直到一次我們物理老師來上課,這個老師年齡偏大,是市裡面的特級教師(恩,應該沒錯),正好碰到餘震,大家又瘋了似得準備往外跑,這時候老師說了一句話,讓我至今
難忘,命在骨子裡,這種餘震沒必要這麼慌擠下去,命硬的怎麼都沒事,確實,這種小餘震擠下去可能更容易發生事故,雖然這句話帶了少許的消極,但裡面更多的是心態的平靜、
心比較大、冷靜果斷的體現,這是我要學習的。

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

更多程式相關知識,請造訪:程式設計影片! !

以上是淺談PHP Closure類及其用法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:cnblogs.com。如有侵權,請聯絡admin@php.cn刪除