深刻了解PHP的生成器

在駕駛方面,速度並不會決定一切。可是在網絡上,速度相當重要。你的應用程序越快,用戶體驗就越好。好吧,這時候有人就奇怪了,本文是關於PHP 生成器的,那麼爲何咱們要談論速度呢?很快你就會發現,生成器在速度和內存管理上產生了巨大的差別。php

PHP生成器是什麼?

在5.5版的PHP中添加了生成器,這些生成器提供了一種簡單的方法來遍歷數據而無需在內存中構建數組的功能。仍是有點困惑嗎?那舉一個例子是顯示生成器運行狀況的好方法。數據庫

首先,讓咱們快速建立一個咱們將在本教程中使用的generator.php文件。建立文件後,咱們添加一小段代碼。數組

<?php

function getRange ($max = 10) {
    $array = [];

    for ($i = 1; $i < $max; $i++) {
        $array[] = $i;
    }

    return $array;
}

foreach (getRange(15) as $range) {
    echo "Dataset {$range} <br>";
}

 

咱們能夠在建立generator.php文件的目錄中快速啓動內置的PHP服務器:瀏覽器

php -S localhost:8000

 

因此若是咱們去 http:// localhost:8000 / generator.php,咱們應該會獲得這樣的東西。服務器

該代碼幾乎是不言自明的,並且看起來絕對不是不少。可是,若是咱們返回代碼並進行一些更改,以下網絡

<?php

foreach (getRange(PHP_INT_MAX) as $range) {
    echo "Dataset {$range} <br>";
}

 

如今,生成數字的上限(最大值)是PHP_INT_MAX,這是你的PHP版本能夠達到的最大數字。完成此操做後,轉到瀏覽器並刷新。可是此次,你會注意到此次有一些不一樣的東西。生成器腳本引起警告錯誤。函數


好吧,這很惋惜,PHP用盡了內存。我想到的解決方案可能包括進入php.ini以及增長memory_limit的上限。讓咱們問問本身這些問題,這真的有效嗎?咱們是否要一個腳原本佔用服務器的全部內存?答案是否認的。這是無效的,而且咱們不但願單個腳本用完咱們全部的內存。性能

使用生成器

讓咱們定義上面的相同函數,使用相同的值PHP_INT_MAX調用它,而後再次運行它。可是,此次,咱們將建立一個生成器函數。spa

<?php

function getRange ($max = 10) {
    for ($i = 1; $i < $max; $i++) {
        yield $i;
    }
}

foreach (getRange(PHP_INT_MAX) as $range) {
    echo "Dataset {$range} <br>";
}

 

剖析getRange函數,這一次,咱們僅遍歷值和yield輸出。yield相似於return,由於它也是從函數返回值,可是惟一的區別是yield僅在須要時才返回值,而且不會嘗試將整個數據集保留在內存中。日誌

若是轉到瀏覽器,應該會看到頁面上顯示的數據。給定適當的時間,瀏覽器最終將顯示數據。

注意:只能經過函數使用生成器。

爲何這樣作?

有時,咱們可能想解析大型數據集(能夠是日誌文件),或者對大型數據庫結果執行計算等。咱們不但願這樣的操做佔用全部內存。咱們應該嘗試儘量地節省內存。數據沒必要必定很大-無論數據集多麼小,生成器都是有效的。別忘了,咱們的目標是使用更少的內存來提升速度。

返回鍵

有時,只有當數據是基於key-value時,咱們的數據纔有意義。使用生成器時,咱們能夠產生這樣的鍵值對。

<?php

function getRange ($max = 10) {
    for ($i = 1; $i < $max; $i++) {
        $value = $i * mt_rand();

        yield $i => $value;
    }
}

 

而後,咱們能夠像使用任何這樣的數組同樣繼續使用該鍵值對。

<?php

foreach (getRange(PHP_INT_MAX) as $range => $value) {
    echo "Dataset {$range} has {$value} value<br>";
}

 

將值發送到生成器

生成器也能夠接受值。這意味着生成器容許咱們將值注入到它們中,多是做爲命令或其餘方式。例如,咱們能夠向生成器發送一個值,告訴它中止執行或更改輸出。使用上面的getRange函數,咱們能夠作到這一點。

<?php

function getRange ($max = 10) {
    for ($i = 1; $i < $max; $i++) {
        $injected = yield $i;

        if ($injected === 'stop') return;
    }
}

 

要發送注入該值,咱們能夠這樣作。

<?php

$generator = getRange(PHP_INT_MAX);

foreach ($generator as $range) {
    if ($range === 10000) {
        $generator->send('stop');
    }

    echo "Dataset {$range} <br>";
}

 

注意:在生成器中使用return會中斷生成器功能。

不要濫用生成器

使用PHP_INT_MAX有點麻煩。對我來講,PHP_INT_MAX是2147483647,即:

二十一億四千七百四十八萬三千六百四十七

生成器應該是內存有效的。這並不意味着若是使用不當,它們不會引發他們試圖解決的相同問題。

結論

生成器提供了咱們難以忽視的性能提高。大多數時候,咱們不須要強大的服務器來處理咱們的代碼。咱們只須要作一些重構。生成器頗有用,咱們應該更多地使用它們。

原文地址:https://scotch.io/tutorials/understanding-php-generators

今日就分享到這啦,若是任何問題或者建議,歡迎留言交流。

相關文章
相關標籤/搜索