0,0
рейтинг
16 июля 2012 в 16:11

Разработка → Если бы в PHP были выделения списков и генераторы перевод

PHP*
Несколько недель назад в списке рассылки PHP было интересное предложение с чьим-то хаком, где описаны генераторы, выражения-генераторы и выделения списков. Неудивительно, что некоторые люди не уверены в перспективах этого предложения, как и core разработчики, так и пользователи PHP. Я хотел бы поделиться несколькими идеями и попытаться убедить этих парней.

Декларативный разбор XML


Самый быстрый пример, который я смог придумать, это простой интерфейс для парсинга больших XML файлов.

<?php

function *readXML($file) {
  $r = new XMLReader;
  $r->open($file);

  while($r->read()) {
    yield $r;
  }
}

function *filterNodes(callable $predicate, $nodes) {
  foreach($nodes as $node) if($predicate($node)) yield $node;
}

function matchName($name) {
  return function($node) use($name) {
    return $node->name === $name;
  };
}

И возможный вариант парсинга с использованием этих функций.

<?php

function *getArticlesFromXML($file) {
  foreach(filterNodes(matchName('article'), readXML($file)) as $node)
    yield nodeToArticle($node);
}

function nodeToArticle($node) {
  // transform node
  return $node->name;
}

$articles = [foreach(getArticlesFromXML('data.xml') as $article) yield $article];

Я уверен, что те, кто уже использовал XMLReader, поймут, как контроль за парсингом был взят из цикла while, и «скорректирован» в декларативный стиль с помощью функций высшего порядка.

Простая декорация итераторов


Это не общий паттерн, но когда мне приходится общаться со внешними сервисами мне нравится оборачивать их ответ в две части:

  • статусная информация — ok, failure, retry-action, get-from-cache и т.д.
  • результаты — обернутые в итератор, который декорирует их во время доступа.


Как я говорил, я не видел похожее в чужом коде, но для меня это частый паттерн, который с использованием генераторов стал проще.

<?php

// inside some class
public function getResult() {
  return SomeCustomIterator($this->results, new SomeCustomDecorator);
}

// with generators
public function *getResults() {
  foreach($this->results as $result)
    yield new SomeCustomDecorator($result);
}


Снова о более выразительном API


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

Не сложно представить себе людей использующих смешанные стили (ООП и процедурное программирование). Они могли бы начать с чего-то простого, например:

<?php
function select() {
  return func_get_args();
}

function from($source) {     
  return $source;
}

function where() {           
  return func_get_args();
}

function *query($select, $from, $where) {
  foreach($from as $element) {      
    foreach($where as $predicate) {   
      if(false === $predicate($element))
        continue 2;
    }
    $fields = array();
    foreach($select as $selector) {   
      $fields[] = $selector($element);
    }
    yield $fields;
  }
}

$articles = query(
  select(property('name')),
  from(readXML('data.xml')),
  where(matchName('article'))
);

// where property could be something as simple as
function property($name) {
  return function($node) use ($name) {
    return $node->{$name};
  };
}

А может быть даже построить что-то вроде LINQ? Не то, что уже существует.

Выглядит как Python


Там было несколько комментариев в которых люди заметили этот аспект и были против. Я не понимал тогда и не понимаю сейчас, почему это плохо. Я, например, считаю это хорошей новостью: ни один язык не является совершенным и каждый из них должен стараться включать особенности, которые оказались полезными в других (конечно, с учетом возможности реализации).

Протестируйте сами


Если вы дочитали статью до этих строчек, и не потеряли интерес, я рекомендую перейти в терминал и выполнить следующие команды до того, как вы закроете вкладку.

$ git clone -b addListComprehensions https://github.com/nikic/php-src.git
$ cd php-src
$ ./buildconf
$ ./configure
$ make cli
$ ./sapi/cli/php some-example-file.php
Перевод: Marius Ghita

Похожие публикации

Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (16)

  • +4
    Это было бы круто. Примеры, как мне показалось, достаточно показательны.
    • +2
      С тех пор как увидел генераторы в Python и в Ruby, в PHP мне стало их жутко не хватать…
  • 0
    Выглядит как Python
    А действительно, что плохого в том, что это выглядит как Python? Python гораздо более логичен и красив, чем PHP. Так давайте стремиться перенести красоту и логичность других ЯП и в PHP.

    Вот если бы речь шла, о каком-то нововведении в Питон и сказали бы, что «выглядит как PHP», то да, это был бы действительно повод задуматься :)
    • +1
      Ну вот драфт по геттерам/сеттерам мне очень напомнил C#. К слову yield там тоже есть. И если с генераторами я не так сильно знаком, то геттеры/сеттеры намного более приятны нежели стандартный подход с getFoo/setFoo
      • 0
        геттеры/сеттеры намного более приятны нежели стандартный подход с getFoo/setFoo
        Конечно же. По сути это то же самое, только короче и лаконичнее
        • 0
          Единственный, если это можно назвать минусом, нету возможности чейнить сеттеры, хотя это редко и встретишь.
          • 0
            Ну если очень хочется — setFoo же никто не отменяет ;) Хотя консистентность нарушается, конечно
          • –1
            > хотя это редко и встретишь

            ну и хорошо :)
      • 0
        В интерфейсы их там можно вносить?
        • 0
          Да. Можно.
  • +1
    да, удобная штука, куда идти голосовать?
    • 0
      Лучше спросите куда коммитить. От присоединения к девелопменту имхо толку побольше было бы, чем от +100500 лайков через соцсети.
      • 0
        Я вот си не знаю (вернее, не знаю настолько, чтобы коммитить). А лайкнуть могу =).
  • +4
    обе эти новые штуки — это элементы функционального программирования. Просто не всем эта парадигма по душе, вот и бурчат.
    К сожалению, есть много программистов на РНР, которые не могут осилить даже функцию crypt (обходятся sha1, md5) — об этом говорилось в той же статье, в пункте про добавление функции для bcrypt. Так вот, ленивые вычисления не по силам таким ленивым программистам.
    В принципе, я и ожидал, что со временем в РНР будут появляться новые элементы функционального программирования. Уже в 5.3 добавили лямбда-функции, конечно же, на этом не могло всё закончиться :)
  • –4
    Может лучше язык сменить на нормальный, а не насиловать труп?
    • 0
      Смена языка это достаточно кардинальное решение. Да и я допустим смысла особо не вижу. Я могу реализовать на PHP все тоже что и на Java/C#. Возможно местами не так лаконично, возможно меньше качественных решений, но и в сфере WEB PHP более универсальное средство, более простое в работе. Не нужен сервер с виндой (Mono все же не полностью реализует функционал .NET фреймворка) и не нужно нагружать сервер Явой (несмотря на более высокую производительность и кошерные плюшки нежели PHP, мне Java Нравится много меньше C#, мелочами в основном). Я когда-то пробовал Питон, но все же что бы найти достойную работу питонщиком уровня знаний у меня не хватает. Подтянуть можно, но это надо целенаправленно учить. Ruby же вообще никак не люблю. Вот хоть убей. Причем это скорее психологическое отвращение, лишенное объективных фактов. Просто вот бесит и все.

      Ну а если дадут проект который быстрее (в разы) сделать на том же .NET — буду делать на нем. Но пока таких среди моих был лишь один, и то только из-за использования OpenCV (в виде биндинга Emgu)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.