класс mysqli_result PHP реализует интерфейс Traversable в течение некоторого времени. Это дает некоторые интересные возможности, такие как следующий фрагмент кода:
<?php $db = new mysqli( '...' ); $result = $db->query( '...' ); foreach( $result as $row ) { //$row is an associative array containing the fetched values }
Теперь мне это очень нравится, но в библиотеке, в которой я сейчас работаю, я хотел бы иметь объекты , а не ассоциативные массивы . Я также хочу иметь возможность передать ему класс, поэтому я могу создать с ним простую модельную систему
Для этого я делаю это следующим образом:
<?php class mysqli_result_extension extends mysqli_result { protected $result_class; public function set_result_class( $class ) { $this->result_class = $class; } public function function_to_overwrite() { return $this->fetch_object( $this->result_class ); } }
Моя проблема и мой вопрос к вам:
Как переключиться с fetch_assoc на fetch_object сейчас? Я хотел бы перезаписать метод, используемый интерфейсом Traversable, чтобы вернуть результат, но он не определяет ( http://php.net/manual/en/class.traversable.php )
Итак, что мне нужно будет перезаписать, чтобы переключиться с fetch_assoc на fetch_object и чтобы передать мне $ result_class, чтобы я мог сделать что-то вроде этого:
<?php $db = new mysqli_extension( '...' ); $posts = $db->query( 'select * from posts' ); //$result is object of type mysqli_result_extension $posts->set_result_class( 'post' ); foreach( $posts as $post ) { //$post is an instance of class 'post' }
Я не хочу, чтобы что-то грязное, взломанное, как перезапись fetch_assoc и просто возвращающий объект в нем
Заранее благодарим за помощь и помощь
Как я уже сказал в комментариях, легко сделать то, что вы хотите с PDO. Просто установите атрибут PDO::ATTR_DEFAULT_FETCH_MODE
, и он будет делать соответствующий вид извлечения, когда вы выполняете цикл foreach.
Вы также можете установить атрибут PDO::ATTR_STATEMENT_CLASS
для определения используемого класса.
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_CLASS); $pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS,array('classname',$constructorArgs));
См. http://php.net/manual/en/pdo.setattribute.php для получения дополнительной информации.
С помощью этого решения вам нужно будет изменить атрибут ATTR_STATEMENT_CLASS
для каждого запроса, в зависимости от того, какой класс вы хотите создать.
Кроме того, вы можете установить его для указания имени класса в запросе:
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE); $stmt = $db->query("SELECT 'classname', * FROM `table` WHERE `id` = 1;");
Просто добавьте соответствующее имя класса в ваш запрос в качестве первого выбранного поля.
См. Один из ответов на этот связанный вопрос. В PHP. Как установить класс выбора класса PDO по умолчанию? для получения дополнительной информации об этом.
На вызов (назовем это) метод traversal-fetch для mysqli_result
нельзя повлиять. Так как по умолчанию ассоциативный массив (имя-столбца как ключ и его значение как значение), как mysqli_result::fetch_assoc()
он остается с этим.
Поэтому для этого требуется собственный Iterator
который выполняет эту работу. Итак, как выглядит традиционная итерация результата Mysqli, отличная от foreach? Правильно, цикл while()
:
while($row = $result->fetch_assoc()) { ... }
Что читает: пока метод fetch не возвращает NULL
продолжайте. Это обычная форма для создания итерации.
Для итераций такого типа я обычно использую FetchingIterator
, это конкретный итератор, который превращает PHP-специфический интерфейс Iterator
(перемотка, действительный, текущий, ключ, следующий) в более упрощенный. Это упрощенно: следующий по перемотке, следующий на следующий и действительный до NULL
– который почти такой же, как и цикл while, и может использоваться для аналогичных рабочих API, таких как устаревшие mysql или даже массивы (сравните array_shift
и т. Д.). Он также похож на другие реализации итераторов на разных языках программирования, здесь, в частности, на Java (сравните образец шаблона проектирования Iterator (руководство по созданию источника на шаблонах проектирования) ).
Я описал это рудиментарно в прошлом году в моей статье « Some PHP Iterator Fun» (февраль 2012 г.), и значительно улучшенная стандартная реализация этого может быть найдена как FetchingIterator
в Iterator Garden, который легко позволяет делать то, что вы хотите сделать.
Давайте посмотрим пример приложения:
class ObjectFetchIterator extends FetchingIterator { public function __construct(mysqli_result $result, $class) { parent::__construct(function() use ($result, $class) { return $result->fetch_object($class); }); } }
Метод mysqli_result::fetch_object()
который ранее был в пределах while(...)
, теперь был перемещен в конструктор FetchingIterator
для результатов mysqli. Тогда это довольно простая реализация. В качестве альтернативы, также можно переопределить защищенный fetchNext()
но я его fetchNext()
только потому, что он здесь не нужен.
Пример использования довольно прост:
$db = new mysqli('...'); $result = $db->query('...'); $iterator = new ObjectFetchIterator($result, 'myClass'); /* @var $row myClass */ foreach ($iterator as $row) { // $row is a myClass now based on fetched values }
Как показывает этот пример, нет необходимости использовать PDO для этого, и это звучит как довольно ленивое оправдание: изменение всего слоя базы данных только для этой маленькой детали? Нет! Противоположный случай: использование итератора здесь, в foreach
позволяет foreach
ваш код от конкретной библиотеки доступа к базе данных до типичного типа (как это было возможно и с массивами ранее, однако массивы далеко не так различны, как типы объектов).
Надеюсь, что это поможет даже ответить немного поздно. Только что привлекло мое внимание, на этот вопрос пока не ответил.
Заметка:
Это внутренний интерфейс движка, который не может быть реализован в PHP-скриптах. Вместо этого следует использовать либо IteratorAggregate, либо Iterator. При реализации интерфейса, который расширяет Traversable, обязательно перечислите IteratorAggregate или Iterator перед его именем в предложении implements.
т.е. вы найдете определение интерфейса по адресу http://docs.php.net/class.iterator и / или http://docs.php.net/class.iteratoraggregate