搜尋
首頁後端開發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中文網其他相關文章!

陳述
本文轉載於:zhihu。如有侵權,請聯絡admin@php.cn刪除
如何使PHP應用程序更快如何使PHP應用程序更快May 12, 2025 am 12:12 AM

tomakephpapplicationsfaster,關注台詞:1)useopcodeCachingLikeLikeLikeLikeLikePachetoStorePreciledScompiledScriptbyTecode.2)MinimimiedAtabaseSqueriSegrieSqueriSegeriSybysequeryCachingandeffeftExting.3)Leveragephp7 leveragephp7 leveragephp7 leveragephpphp7功能forbettercodeefficy.4)

PHP性能優化清單:立即提高速度PHP性能優化清單:立即提高速度May 12, 2025 am 12:07 AM

到ImprovephPapplicationspeed,關注台詞:1)啟用opcodeCachingwithapCutoredUcescriptexecutiontime.2)實現databasequerycachingingusingpdotominiminimizedatabasehits.3)usehttp/2tomultiplexrequlexrequestsandreduceconnection.4 limitesclection.4.4

PHP依賴注入:提高代碼可檢驗性PHP依賴注入:提高代碼可檢驗性May 12, 2025 am 12:03 AM

依赖注入(DI)通过显式传递依赖关系,显著提升了PHP代码的可测试性。1)DI解耦类与具体实现,使测试和维护更灵活。2)三种类型中,构造函数注入明确表达依赖,保持状态一致。3)使用DI容器管理复杂依赖,提升代码质量和开发效率。

PHP性能優化:數據庫查詢優化PHP性能優化:數據庫查詢優化May 12, 2025 am 12:02 AM

DatabasequeryoptimizationinPHPinvolvesseveralstrategiestoenhanceperformance.1)Selectonlynecessarycolumnstoreducedatatransfer.2)Useindexingtospeedupdataretrieval.3)Implementquerycachingtostoreresultsoffrequentqueries.4)Utilizepreparedstatementsforeffi

簡單指南:帶有PHP腳本的電子郵件發送簡單指南:帶有PHP腳本的電子郵件發送May 12, 2025 am 12:02 AM

phpisusedforsenderemailsduetoitsbuilt-inmail()函數andsupportivelibrariesLikePhpMailerAndSwiftMailer.1)usethemail()functionForbasiceMails,butithasimails.2)butithasimail.2)

PHP性能:識別和修復瓶頸PHP性能:識別和修復瓶頸May 11, 2025 am 12:13 AM

PHP性能瓶颈可以通过以下步骤解决:1)使用Xdebug或Blackfire进行性能分析,找出问题所在;2)优化数据库查询并使用缓存,如APCu;3)使用array_filter等高效函数优化数组操作;4)配置OPcache进行字节码缓存;5)优化前端,如减少HTTP请求和优化图片;6)持续监控和优化性能。通过这些方法,可以显著提升PHP应用的性能。

PHP的依賴注入:快速摘要PHP的依賴注入:快速摘要May 11, 2025 am 12:09 AM

依賴性注射(DI)InphpisadesignPatternthatManages和ReducesClassDeptions,增強量強制性,可驗證性和MATIALWINABIOS.ItallowSpasspassingDepentenciesLikEdenciesLikedAbaseConnectionStoclasseconnectionStoclasseSasasasasareTers,interitationAseTestingEaseTestingEaseTestingEaseTestingEasingAndScalability。

提高PHP性能:緩存策略和技術提高PHP性能:緩存策略和技術May 11, 2025 am 12:08 AM

cachingimprovesphpermenceByStorcyResultSofComputationsorqucrouctationsorquctationsorquickretrieval,reducingServerLoadAndenHancingResponsetimes.feftectivestrategiesinclude:1)opcodecaching,whereStoresCompiledSinmememorytssinmemorytoskipcompliation; 2)datacaching datacachingsingMemccachingmcachingmcachings

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具