Генераторы в PHP 5.5
Самым большим нововведением (и очень важным для языка) в PHP 5.5.0 будут генераторы. Я установил себе
Посмотрите на код, который я написал, пока мы ждали всех участников встречи, на которую я был приглашён:
<?
function enumerate($arr)
{
$i = 0;
foreach ($arr as $value) {
yield [$i++, $value];
}
}
function ifilter(callable $predicate = null, $arr)
{
if ($predicate === null) {
$predicate = 'boolval';
}
foreach ($arr as $value) {
if ($predicate($value)) {
yield $value;
}
}
}
function islice($arr, $start, $stop)
{
if (is_array($arr)) {
reset($arr);
for ($i = $start; $i > 0 && each($arr); $i--);
for ($i = $stop - $start + 1; $i > 0 && list(,$value) = each($arr); $i--) {
yield $value;
}
} else {
for ($i = $start; $i > 0 && $arr->valid(); $i--) {
$arr->next();
}
for ($i = $stop - $start; $i > 0 && $arr->valid(); $i--) {
yield $arr->current();
$arr->next();
}
}
}
$array = [10, 20, 30, 33, 40, 50, 60];
$gen = islice(
enumerate(
ifilter(
function($x) { return ($x % 10) === 0; },
$array
)),
1, 4
);
foreach ($gen as $value) {
print_r($value);
}Три генератора, пропускающие через себя данные, обрабатывают массив, всё работает. Названия взяты из Пайтона. Первый нумерует входящий поток данных (возвращает пары номер и значение), второй фильтрует значения через функцию, третий отрезает заданную часть от входных данных.
Концепция генераторов проста, как герань. PHP поддерживает два способа их создания (как и Пайтон), но мне милее оператор yield. Работает он примерно как return, но при повторном входе в функцию её выполнение происходит не сначала, а с того места, откуда управление было возвращено при помощи yield. Можно ещё передавать значения внутрь генератора, но я про это сейчас не буду. Вцелом, получаются настоящие ленивые вычисления — всё это вызывается ровно тогда, когда это реально нужно.
Генераторы, обычно, работают с итерируемыми объектами — возращают их и/или принимают. Итерируемый объект, проще говоря, это то, по чему можно пробежаться циклом. Генераторы, кстати, тоже итерируемые.
И вот тут опять проявляются недостатоки PHP: отсутствие общей логики, непродуманность.
Массив тут до сих пор примитивный тип и он требует иной способ обработки. Посмотрите на генератор islice, тут проблема видна во всей красе. Начинается она уже с хинтинга, я не могу потребовать от $arr быть типа array, потому что на вход может прийти другой генератор, и указать класс генератора тоже не могу — массив ему не принадлежит. Думаю, следует ожидать появления нового типа «iterable», как это уже случилось с callable.
Вторая проблема ещё более серьёзная. У массива нет методов (он же примитивный тип), а генераторы,
Мне кажется, PHP следует развивать класс ArrayObject, который уже присуствует в языке и делать прозрачное преобразование примитивных типов в объекты (как это происходит в JavaScript), это решило бы некоторые проблемы.
Наведение порядка в PHP (версия 5.5.0)
Нужно ещё похвалить авторов PHP за то, что они действительно стараются навести порядок в языке. С каждой версией он становится немного логичнее.
Например, теперь уже можно сделать вот так:
[
POW => function($x) { return $x*$x; },
SIN => function($x) { return sin($x); },
][$selector]Правда, всё ещё нельзя вызвать функцию сразу. В 5.5.0 будет работать вот такая вещь:
if (empty(somefunc())) { /* … */}Но то же самое нельзя сделать с isset, так как сложно сказать что это будет значить — в языке нет отдельного неопределённого значения переменной, она бывает только недекларированной; функция, конечно, может её вернуть, но на самом деле вернётся NULL, а isset от значения NULL — «ложь».
Появилась возможность использовать list внутри цикла следующим образом:
foreach ($somehash as list($key, $value)) { /* … */ }И сделано ещё несколько мелочей, но работы впереди ещё много.