Рассматриваем PHP генераторы

0
1207

Рассматриваем PHP генераторы

PHP генераторы — полезное понятие, чтобы понять мир разработки PHP.

Когда дело доходит до управления автомобилем, скорость — это не все, что необходимо. Но в интернете, скорость означает нечто иное. Чем быстрее ваше приложение, тем лучше опыт пользователя. Эта статья посвящена PHP генераторам, но почему мы говорим о скорости? Скоро вы поймете, генераторы имеют большое влияние на скорость и управление памятью.

Что такое PHP генераторы?

Добавленные в PHP в версии 5.5, генераторы являются функциями, которые обеспечивают простой способ для перебора данных без необходимости создания массива в памяти. Еще немного путаетесь? Пример — хороший способ показать генераторы в действии.

Во-первых, быстро создадим файл generator.php который мы будем использовать в этом руководстве. После создания файла, мы добавим этот небольшой фрагмент кода.

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

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

    return $array;
}

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

Мы можем быстро распаковать встроенный PHP-сервер в каталог, где мы создали файл generator.php:

php -S localhost:8000

Поэтому если мы перейдем по адресу (http://localhost:8000/generator.php), мы получим что-то вроде следующего:

Dataset 1
Dataset 2
Dataset 3
Dataset 4
Dataset 5
Dataset 6
Dataset 7
Dataset 8
Dataset 9
Dataset 10
Dataset 11
Dataset 12
Dataset 13
Dataset 14
Dataset 15

Код скажет все сам за себя, и его, безусловно, не так много. Но если мы вернемся в наш код и сделаем небольшие изменения, то получим:

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

Теперь upper range (max) с сгенерированных чисел — PHP_INT_MAX, что является наибольшим числом, которого может достичь ваша версия PHP. После этого, зайдите в браузер и обновите его. Но на этот раз вы увидите что-то другое. Генератор выдаст ошибку.

Fatal error: Allowed memory size of 209715200 bytes exhausted (tried to allocate 4104 bytes) in X:\home\localhost\www\bookflow\includes\index.php on line 637

Состоялось переполнения памяти. Возможные решения, которые приходят на ум: обратиться в php.ini и увеличить memory_limit. Зададим себе вопрос, действительно ли это будет эффективно? Хотим ли мы иметь один скрипт, который будет содержать всю память нашего сервера? Ответы — нет и нет. Это не эффективно, и мы не хотим скрипт, который будет использовать всю нашу память.

Использование генераторов

Определим ту же функцию, которую использовали выше, вызовем ее с тем же значением PHP_INT_MAX и запустим программу. Но, на этот раз, мы будем создавать функцию-генератор.

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

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

Рассматривая функцию getRange, мы только выполняем цикл по значениям и даем исходную информацию — yield. yield похож на return, поскольку он возвращает значение из функции, но с той лишь разницей, что yield возвращает значение только тогда, когда это необходимо, и не пытается сохранить весь набор данных в памяти.

Если вы зайдете в свой браузер, вы должны увидеть данные, которые отображаются на странице.

Примечание: Генераторы могут быть использованы только в функции.

Зачем нужны генераторы?

Есть моменты, когда мы хотели бы разобрать большой набор данных (это могут быть лог-файлы), выполнять вычисления на больших базах данных и т.д. Но мы не хотим искажать всю память. Мы должны стараться сохранить память как можно дольше. Данные не обязательно должны быть большими — генераторы являются эффективными независимо от того, насколько маленький набор данных. Не забывайте, что наша цель заключается в увеличении скорости при использовании меньшего количества памяти.

Возвращаемые значения

Есть моменты, когда наши данные имеют смысл только тогда, когда они являются ключевыми. При использовании генераторов, мы можем возвращать значение, например:

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

Затем мы можем пойти дальше и использовать пары значений, поскольку мы могли бы сделать это с любым массивом, например:

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

Отправка переменных к генераторам

Генераторы могут также принимать переменные. Это означает, что генераторы позволяют вводить значения в них, это может быть команда или что-то другое. Например, мы можем послать переменную к нашему генератора, чтобы остановить выполнение или изменить output. С помощью функции getRange, которая уже была приведена выше, мы можем сделать это:

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

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

Передача значения, сделайте следующее:

$generator = getRange(PHP_INT_MAX);

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

    echo "Dataset {$range} 
";
}

Примечание: Использование return в генераторе нарушит функцию генератора.

Не злоупотребляйте генераторами

Использование PHP_INT_MAX немного неуместно. Для меня PHP_INT_MAX это 2147483647, а именно:

Генераторы должны быть эффективными. Это не значит, что они не будут вызывать ту же проблему, которую они пытаются решить при неправильном использовании.

ОСТАВЬТЕ ОТВЕТ

Please enter your comment!
Please enter your name here