首頁 後端開發 php教程 帶你詳解PHP生成器的使用

帶你詳解PHP生成器的使用

Dec 01, 2020 pm 01:50 PM
php生成器

學習PHP生成器的使用

什麼是生成器?

聽著高大上的名字,感覺像是創造東西的功能,實際上,生成器是一個用於迭代的迭代器。它提供了一種更容易的方式來實現簡單的物件迭代,相比較定義類別實作Iterator介面的方式,效能開銷和複雜性大大降低。

推薦:《PHP影片教學

說了半天不如直接看看程式碼更直覺。

function test1()
{
    for ($i = 0; $i < 3; $i++) {
        yield $i + 1;
    }
    yield 1000;
    yield 1001;
}
foreach (test1() as $t) {
    echo $t, PHP_EOL;
}
// 1
// 2
// 3
// 1000
// 1001
登入後複製

就是這麼簡單的一段程式碼。首先,生成器必須在方法中並使用 yield 關鍵字;其次,每一個 yield 可以看作是一次 return ;最後,外部循環時,一次循環取一個 yield 的回傳值。在這個例子,循環三次回傳了1、2、3這三個數字。然後在循環外部又寫了兩行 yield 分別輸出了1000和1001。因此,外部的 foreach 一共循環輸出了五次。

很神奇吧,明明是一個方法,為什麼能夠循環它而且還是很奇怪的一種返回循環體的格式。我們直接列印這個 test() 方法看看列印的是什麼:

// 是一个生成器对象
var_dump(test1());
// Generator Object
// (
// )
登入後複製

當使用了 yield 進行內容回傳後,傳回的是一個 Generator 物件。這個物件就叫作生成器對象,它不能直接被 new 實例化,只能透過生成器函數這種方式返回。這個類別包含 current() 、 key() 等方法,而且最主要的這個類別實作了 Iterator 接口,所以,它就是一個特殊的迭代器類別。

Generator implements Iterator {
    /* 方法 */
    public current ( void ) : mixed
    public key ( void ) : mixed
    public next ( void ) : void
    public rewind ( void ) : void
    public send ( mixed $value ) : mixed
    public throw ( Exception $exception ) : void
    public valid ( void ) : bool
    public __wakeup ( void ) : void
}
登入後複製

生成器有什麼用?

搞了半天不就是個迭代器嘛?搞這麼麻煩幹嘛,直接用迭代器或是在方法中直接回傳一個陣列不就好了嗎?沒錯,正常情況下真的沒有這麼麻煩,但是如果是在數據量特別大的情況下,這個生成器就能發揮它的強大威力了。生成器最強大的部分就在於,它不需要一個陣列或任何的資料結構來保存這一系列資料。每次迭代都是程式碼執行到 yield 時動態傳回的。因此,生成器能夠極大的節約記憶體。

// 内存占用测试
$start_time = microtime(true);
function test2($clear = false)
{
    $arr = [];
    if($clear){
        $arr = null;
        return;
    }
    for ($i = 0; $i < 1000000; $i++) {
        $arr[] = $i + 1;
    }
    return $arr;
}
$array = test2();
foreach ($array as $val) {
}
$end_time = microtime(true);
echo "time: ", bcsub($end_time, $start_time, 4), PHP_EOL;
echo "memory (byte): ", memory_get_usage(true), PHP_EOL;
// time: 0.0513
// memory (byte): 35655680
$start_time = microtime(true);
function test3()
{
    for ($i = 0; $i < 1000000; $i++) {
        yield $i + 1;
    }
}
$array = test3();
foreach ($array as $val) {
}
$end_time = microtime(true);
echo "time: ", bcsub($end_time, $start_time, 4), PHP_EOL;
echo "memory (byte): ", memory_get_usage(true), PHP_EOL;
// time: 0.0517
// memory (byte): 2097152
登入後複製

上述程式碼只是簡單的進行 1000000 個循環後取得結果,不過也可以直觀地看出。使用生成器的版本僅消耗了 2M 的內存,而未使用生成器的版本則消耗了 35M 的內存,直接已經10多倍的差距了,而且越大的量差距超明顯。因此,有大神將生成器說成是PHP中最被低估了的特性。

生成器的應用

接下來我們來看看生成器的一些基本的應用方式。

回傳空值以及中斷

產生器當然也可以回傳空值,直接 yield; 不帶任何值就可以回傳一個空值了。而在方法中直接使用 return; 也可以用來中斷生成器的繼續執行。下面的程式碼我們在 $i = 4; 的時候回傳的是個空值,也就是不會輸出 5 (因為我們回傳的是 $i 1 )。然後在 $i == 7 的時候

使用 return; 中斷生成器的繼續執行,也就是循環最多只會輸出到 7 就結束了。

// 返回空值以及中断
function test4()
{
    for ($i = 0; $i < 10; $i++) {
        if ($i == 4) {
            yield; // 返回null值
        }
        if ($i == 7) {
            return; // 中断生成器执行
        }
        yield $i + 1;
    }
}
foreach (test4() as $t) {
    echo $t, PHP_EOL;
}
// 1
// 2
// 3
// 4
// 5
// 6
// 7
登入後複製

返回鍵值對形式

不要驚訝,生成器真的是可以返回鍵值對形式的可遍歷對象供foreach 使用的,而且語法非常好記: yield key = > value; 是不是跟數組項的定義形式一模一樣,非常直觀好理解。

function test5()
{
    for ($i = 0; $i < 10; $i++) {
        yield &#39;key.&#39; . $i => $i + 1;
    }
}
foreach (test5() as $k=>$t) {
    echo $k . &#39;:&#39; . $t, PHP_EOL;
}
// key.0:1
// key.1:2
// key.2:3
// key.3:4
// key.4:5
// key.5:6
// key.6:7
// key.7:8
// key.8:9
// key.9:10
登入後複製

外部傳遞資料

我們可以透過 Generator::send 方法來向生成器中傳入一個值。傳入的這個值將會被當作生成器目前 yield 的回傳值。然後我們根據這個值可以做一些判斷,例如根據外部條件中斷生成器的執行。

function test6()
{
    for ($i = 0; $i < 10; $i++) {
        // 正常获取循环值,当外部send过来值后,yield获取到的就是外部传来的值了
        $data = (yield $i + 1);
        if($data == &#39;stop&#39;){
            return;
        }
    }
}
$t6 = test6();
foreach($t6 as $t){
    if($t == 3){
        $t6->send(&#39;stop&#39;);
    }
    echo $t, PHP_EOL;
}
// 1
// 2
// 3
登入後複製

上述程式碼理解起來可能比較繞,但是注意記住註解的那行話就行了(​​正常取得循環值,當外部send過來值後,yield取得到的就是外部傳來的值了) 。另外,變數取得 yield 的值,必須用括號括起來。

yield from 語法

yield from 語法其實就是指的從另一個可迭代物件中一個一個的獲取資料並形成生成器返回。直接看代碼。

function test7()
{
    yield from [1, 2, 3, 4];
    yield from new ArrayIterator([5, 6]);
    yield from test1();
}
foreach (test7() as $t) {
    echo &#39;test7:&#39;, $t, PHP_EOL;
}
// test7:1
// test7:2
// test7:3
// test7:4
// test7:5
// test7:6
// test7:1
// test7:2
// test7:3
// test7:1000
登入後複製

在 test7() 方法中,我們使用 yield from 分別從普通數組、迭代器物件、另一個生成器中獲取資料並做為當前生成器的內容進行傳回。

小驚喜

#產生器可以用count取得數量嗎?

抱歉,生成器是不能用count來取得它的數量的。

$c = count(test1()); // Warning: count(): Parameter must be an array or an object that implements Countable
// echo $c, PHP_EOL;
登入後複製

使用 count 來取得生成器的數量將直接回報 Warning 警告。直接輸出將會一直顯示是 1 ,因為 count 的特性(強制轉換成陣列都會顯示 1 )。

使用生產器來取得斐波那契數列

// 利用生成器生成斐波那契数列
function fibonacci($item)
{
    $a = 0;
    $b = 1;
    for ($i = 0; $i < $item; $i++) {
        yield $a;
        $a = $b - $a;
        $b = $a + $b;
    }
}
$fibo = fibonacci(10);
foreach ($fibo as $value) {
    echo "$value\n";
}
登入後複製

這段程式碼就不多解釋了,非常直覺的一段程式碼了。

總結

#

生成器絕對是PHP中的一個隱藏的寶藏,不僅是對於內存節約來說,而且語法其實也非常的簡潔明了。我們不需要在方法內部再多定義一個陣列去儲存回傳值,直接 yield 一項一項的回傳就可以了。在實際的專案中完全值得嘗試一把,但是嘗試完了別忘了和小伙伴們分享,大部分人可能真的沒有接觸過這個特性哦! !

測試程式碼: https://github.com/zhangyue0503/dev-blog/blob/master/php/202002/source/學習PHP產生器的使用.php

#參考文件: https://www.php.net/manual/zh/language.generators.overview.php https://www.php.net/manual/zh/class.generator.php

######

以上是帶你詳解PHP生成器的使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

解釋PHP中晚期靜態結合的概念。 解釋PHP中晚期靜態結合的概念。 Mar 21, 2025 pm 01:33 PM

文章討論了PHP 5.3中介紹的PHP中的晚期靜態結合(LSB),允許靜態方法的運行時間分辨率調用以更靈活的繼承。 LSB的實用應用和潛在的觸摸

框架安全功能:防止漏洞。 框架安全功能:防止漏洞。 Mar 28, 2025 pm 05:11 PM

文章討論了框架中的基本安全功能,以防止漏洞,包括輸入驗證,身份驗證和常規更新。

自定義/擴展框架:如何添加自定義功能。 自定義/擴展框架:如何添加自定義功能。 Mar 28, 2025 pm 05:12 PM

本文討論了將自定義功能添加到框架上,專注於理解體系結構,識別擴展點以及集成和調試的最佳實踐。

如何用PHP的cURL庫發送包含JSON數據的POST請求? 如何用PHP的cURL庫發送包含JSON數據的POST請求? Apr 01, 2025 pm 03:12 PM

使用PHP的cURL庫發送JSON數據在PHP開發中,經常需要與外部API進行交互,其中一種常見的方式是使用cURL庫發送POST�...

描述紮實的原則及其如何應用於PHP的開發。 描述紮實的原則及其如何應用於PHP的開發。 Apr 03, 2025 am 12:04 AM

SOLID原則在PHP開發中的應用包括:1.單一職責原則(SRP):每個類只負責一個功能。 2.開閉原則(OCP):通過擴展而非修改實現變化。 3.里氏替換原則(LSP):子類可替換基類而不影響程序正確性。 4.接口隔離原則(ISP):使用細粒度接口避免依賴不使用的方法。 5.依賴倒置原則(DIP):高低層次模塊都依賴於抽象,通過依賴注入實現。

ReactPHP的非阻塞特性究竟是什麼?如何處理其阻塞I/O操作? ReactPHP的非阻塞特性究竟是什麼?如何處理其阻塞I/O操作? Apr 01, 2025 pm 03:09 PM

深入解讀ReactPHP的非阻塞特性ReactPHP的一段官方介紹引起了不少開發者的疑問:“ReactPHPisnon-blockingbydefault....

See all articles