Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Для профи > Проброс yield


Автор: evilice 12.2.2015, 14:13
Всем доброго времени суток!
Пишу модуль для работы с MySQL. Есть основной класс:
Код

namespace mysql;

class Query {
    protected $sql = '';

    /** Other PHP-code **/

    public function execute() {
        return mysql_query($this->sql);
    }
    
    public function map() {
        if($res = $this->execute()) {
            while($map = (mysql_fetch_assoc($res))) {
                yield $map;
            }
        }
    }
}


Данный класс выполняет всю работу с запросами. Решил расширить его работу классом который возьмёт на себя обязанности SQL-конструктора. И чтобы не делать дополнительной работы решил унаследовать SQLConstructor от Query:
Код

namespace mysql;

class SQLConstructor extends \mysql\Query {
    /** Other PHP-code **/
    public function map() {
        $this->convert();
        yield parent::map();
    }
}


Ну и конечно же так я предполагал это всё использовать:
Код

$q = new \mysql\SQLConstructor();
$q->select('test_table', ['@in'=>['key', ['k.1', 'k2']]])->fields('name', 'key');
//--- SQL: select `name`, `key` from `test_table` where `key` in ('k.1', 'k.2')

foreach($q->map() as $data) {
     echo $data['key'].': '.$data['name'];
}


Как я наивно предполагал произойдёт проброс yield из Query в SQLConstruktor и дальше до момента востребования ))).

Если вкратце, то вопрос звучит следующим образом: как работать с yield при наследовании классов.
Заранее спасибо за помощь.

Автор: sQu1rr 13.2.2015, 13:48
Цитата(evilice @  12.2.2015,  11:13 Найти цитируемый пост)
Если вкратце, то вопрос звучит следующим образом: как работать с yield при наследовании классов.

На это я к сожалению ответить не смогу, но я хотел бы спросить, какого, извините, хрена, здесь нужен yield вообще?
Он уменьшает в данном случае читаемость, производительность и увелчивает потребление памяти. Возвращайте просто массив, зачем вам yield?

Автор: baldina 13.2.2015, 15:11
evilice, вот http://ideone.com/idVLWV
sQu1rr, yield немного увеличивает потребление памяти, но по сравнению с размером массива это копейки.

Автор: sQu1rr 13.2.2015, 22:10
baldina, ну да, но я в таком случае вообще не вижу смысла йилда. возврат ссылки на массив даст тот же результат.

Автор: baldina 13.2.2015, 22:17
нет. смысл что бы вообще не создавать массив
не говоря уж что возврат по ссылке это моветон затрудняет понимание и отладку
щас нарисую

Добавлено @ 22:22
ну что-то в этом роде http://ideone.com/ANjtPF

Автор: baldina 13.2.2015, 23:06
evilice, вы используете современные возможности языка, и тут же - устаревший mysql_, который http://php.net/manual/ru/intro.mysql.php. нелогично.

Автор: sQu1rr 16.2.2015, 12:32
Цитата(baldina @  13.2.2015,  19:17 Найти цитируемый пост)
нет. смысл что бы вообще не создавать массив

И правда, внимательность меня порой подводит


Цитата(baldina @  13.2.2015,  19:17 Найти цитируемый пост)
ну что-то в этом роде http://ideone.com/ANjtPF

Сюда бы добавить тест на скорость

Автор: baldina 16.2.2015, 14:08
Цитата(sQu1rr @  16.2.2015,  12:32 Найти цитируемый пост)
Сюда бы добавить тест на скорость 

http://ideone.com/PuMXBL

Автор: sQu1rr 16.2.2015, 15:54
Цитата(baldina @  16.2.2015,  11:08 Найти цитируемый пост)
легко

Если честно, я не понимаю  smile 
Логика мне подсказывает что:
1. Так как мы используем fetchall - memory_usage будет в целом одинаковая, а memory_peak_usage будет равна memory_usage для fetchall - это понятно
2. Скорость будет выше у fetchall так как массив заполняется сразу целиком и дальше мы его просто используем. Имеет ли место быть погрешность из-за того что база находится в оперативной памяти а не на сервере: откуда такая странная разница в скорости?
Или я чего-то не понимаю?

Автор: baldina 16.2.2015, 16:41
пример с бд в памяти имхо наиболее чистый, т.к. нет дополнительных факторов, связанных с диском и сетью
а причины могут быть в том, что
- прокинуть 100k данных нужно время
- массив в php это не массив, поэтому эффективности от последовательного расположения в памяти ждать не приходится
- меньше выделенной ОП - меньше вероятности выпадения в своп и перезагрузки кеша

а накладные расходы yield видимо не так уж велики. щас нарисую с итератором, предполагаю что результат будет похож

Добавлено через 13 минут и 51 секунду
http://ideone.com/WhrM4g
результат примерно как ожидался. с итератором памяти столько же, но медленнее (больше кода интерпретируется)

Автор: sQu1rr 16.2.2015, 17:19
Плюсик вам, спасибо большое smile

Автор: baldina 16.2.2015, 17:32
спасибо)
sQu1rr, я немножко поигрался, вот немного расширенный пример http://ideone.com/NodKJy
видно, что отклонение результатов в тестах с передачей массива больше - это, видимо, свидетельствует о бОльшей зависимости от текущего состояния системы (и/или бОльшего влияния на него) в случае бОльшего потребления ресурсов

Автор: MaXL 2.9.2015, 03:21
Насколько корректно привести код baldina к следующему виду:
Код

    <?php
     
    function foo () {
      for ($x=0; $x != 5; ++$x)
        yield $x;
    }
     
    function bar () {
      return foo();
    }
     
    foreach (bar() as $x)
      echo $x;


Функция foo возвращает генератор, в функции bar мы ничего не изменяем, поэтому можем его просто "пробросить".

Автор: baldina 2.9.2015, 17:02
корректно и практически ничего не меняет в смысле производительности и потребления памяти

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)