iterator to array php
PHP iterable to array or Traversable
I’m quite happy that PHP 7.1 introduced the iterable pseudo-type.
I’m looking for a solution that avoids conditionals in my functions just to take care of this difference, and that does not depend on me defining my own global functions.
7 Answers 7
Not sure this is what are you searching for but this is the shortest way to do it.
I’m not very sure why it works. Just I found your question interesting and I start fiddling with PHP
Is there something like iterable_to_array and iterable_to_traversable
Just add these to your project somewhere, they don’t take up a lot of space and give you the exact APIs you asked for.
Can be done like this:
Terms are easy to mix
In case Iterator type is specified for parameter, passing in an array will cause TypeError.
You can use iterator_to_array converting your variable to Traversable first:
Conversion method is taken from the comment under this question.
For the «iterable to array» case it seems there is no single function call you can make and that you’ll either need to use a conditional in your code or define your own function like this one:
The solution to this problem is too long to post here though I have created a mini-library that contains both conversion functions:
Паттерн проектирования Iterator (Итератор) на PHP
Перед прочтением ознакомьтесь с введением в паттерны проектирования на PHP, в котором описаны принятые соглашения и понятия. Данная статья дополняется с некоторой периодичностью, так что если вы ее читали ранее, не факт что данные не изменились.
Итератор (Iterator) относится к классу поведенческих паттернов. Используется в составных объектах. Предоставляет доступ к своим внутренним полям не раскрывая их структуру.
Зачастую этот паттерн используется вместо массива объектов, чтобы не только предоставить доступ к элементам, но и наделить некоторой логикой. Это может быть ограничение доступа, сортировка или любая другая операция над множеством объектов.
На этом применение паттерна не ограничивается, иногда его удобно использовать для создания своеобразного бесконечного конвейера. Правда с приходом PHP 5.5 на это место придут генераторы
Структура
PHP поддерживает итераторы из коробки, для этого есть 2 интерфейса.
Как видите, структура паттерна очень простая. Iterator это общий интерфейс, позволяющий реализовать произвольную логику итераций. IteratorAggregate более общий, позволяющий использовать готовые итераторы.
Немного о методах интерфейса Iterator
Таким образом, реализуя все методы итератора можно будет делать так:
что соответствует вызовам метода итератора
и на php можно было бы написать как-то так
Реализуем простой итератор по массиву
Встроенные итераторы
В PHP есть набор уже реализованных итераторов список довольно длинный
Среди них есть и ArrayIterator, который я использовал в примере выше
К практике
Реализуем корзину покупок
Вполне резонный вопрос будет, зачем здесь использовать итератор? Можно было заменить getIterator на getPurchases и немного подредактировать код. Да, это так. Но не всегда можно отделаться так легко.
Давайте рассмотрим другой пример. Предположим у нас есть новостной блок, на который выводится 10 новостей.
Скажем он был реализован как-то так:
Предположим что метод getLatestNews используется во многих частях системы, и все клиенты этого кода ожидают в результате массив объектов. При этом оба куска код находятся на достаточном отдалении друг от друга, что бы взаимодействовать им было бы довольно затруднительно. И единственным связующим звеном является переменная $news
Наша задача вывести не только блок новостей, но и общее количество новостей в архиве.
Красивым решением было бы заменить ответ getLatestNews() на объект в который инкапсулированы новости и количество.
Но исходя из условия задачи, для этого придется переписать большое количество кода.
Здесь на помощь может прийти итератор.
В этом случае удалось обойтись малой кровью.
Применимость
Применяйте этот паттерн, если
iterator_apply
(PHP 5 >= 5.1.0, PHP 7, PHP 8)
iterator_apply — Вызывает функцию для каждого элемента в итераторе
Описание
Вызывает функцию для каждого элемента в итераторе.
Список параметров
Объект итератора для перебора.
Аргументы для передачи в функцию обратного вызова. Массив ( array ) аргументов; каждый элемент args передаётся в функцию обратной функции ( callback ) в виде отдельного аргумента.
Возвращаемые значения
Возвращает количество итераций.
Примеры
Пример #1 Пример использования iterator_apply()
Результат выполнения данного примера:
Смотрите также
User Contributed Notes 3 notes
Each of the arguments required by the function, must be in the array supplied in the third argument to iterator_apply. You can use references too. Example:
Not found words:
gasoil
Be aware of the proper methods to iterate the specific Iterator you are consuming, as the implementation of the method could vary its behaviour.
0 =>ze =>Ze
0 =>ze =>Ze
0 =>ze =>Ze
0 =>ze =>Ze
Did iterate 4 times
0 =>ze =>Ze
1 =>ome =>Ome
2 =>yei =>Yei
3 =>nahui =>Nahui
Did iterate 4 times
int(4)
0 Ze
0 Ome
0 Yei
0 Nahui
int(0)
$args is an array and each of its elements are passed to the callback as separate arguments.
so this is the right way to get args:
Iterator to array php
By reading the posts below I wondered if it really is impossible to make an ArrayAccess implementation really behave like a true array ( by being multi level )
Seems like it’s not impossible. Not very preety but usable
class ArrayAccessImpl implements ArrayAccess <
echo «ArrayAccess implementation that behaves like a multi-level array » ;
$data = new ArrayAccessImpl ();
?>
(in the two links mentioned below by artur at jedlinski. they say you can’t use references, so I didn’t used them.
My implementation uses recursive objects)
If anyone finds a better (cleaner) sollution, please e-mail me.
Thanks,
Wave.
The example code given for valid() will break if the array contains a FALSE value. This code prints out a single «bool(true)» and exits the loop when it gets to the FALSE:
Use the SPL ArrayAccess interface to call an object as array:
The MyIterator::valid() method above ist bad, because it
breaks on entries with 0 or empty strings, use key() instead:
To clarify on php at moechofe’s post, you CAN use the SPL to overide the array operator for a class. This, with the new features of object, and autoloading (among a buch of other things) has me completely sold on PHP5. You can also find this information on the SPL portion of the manual, but I’ll post it here as well so it isn’t passed up. The below Collection class will let you use the class as an array, while also using the foreach iterator:
public function doSomething ()
<
echo «I’m doing something» ;
>
>
?>
I LOVE the new SPL stuff in PHP! An example of usage is below:
Just something i noticed:
It seems, that when you are implementing the interface Iterator, yout method key() has to return a string or integer.
I was trying to return a object an got this error:
Illegal type returned from MyClass::key()
One should be aware that ArrayAccess functionality described by «just_somedood at yahoo dot com» below is currently broken and thus it’s pretty unusable.
Beware of how works iterator in PHP if you come from Java!
In Java, iterator works like this :
interface Iterator O > <
boolean hasNext ();
O next ();
void remove ();
>
?>
But in php, the interface is this (I kept the generics and type because it’s easier to understand)
interface Iterator O > <
boolean valid ();
mixed key ();
O current ();
void next ();
void previous ();
void rewind ();
>
?>
1. valid() is more or less the equivalent of hasNext()
2. next() is not the equivalent of java next(). It returns nothing, while Java next() method return the next object, and move to next object in Collections. PHP’s next() method will simply move forward.
Here is a sample with an array, first in java, then in php :
class ArrayIterator O > implements Iterator O > <
private final O [] array;
private int index = 0 ;
public boolean hasNext () <
return index length ;
>
public void remove () <
throw new UnsupportedOperationException ( ‘remove() not supported in array’ );
>
>
?>
And here is the same in php (using the appropriate function) :
Also, another difference :
class ArrayIterable O > implements Iterable O > <
private final O [] array;
public Iterator O > iterator () <
return new ArrayIterator (array);
>
>
?>
When using an Iterable, in Java 1.5, you may do such loops :
The ArrayIterator class
Introduction
This iterator allows to unset and modify values and keys while iterating over Arrays and Objects.
When you want to iterate over the same array multiple times you need to instantiate ArrayObject and let it create ArrayIterator instances that refer to it either by using foreach or by calling its getIterator() method manually.
Class synopsis
Predefined Constants
ArrayIterator Flags
Properties of the object have their normal functionality when accessed as list (var_dump, foreach, etc.).
ArrayIterator::ARRAY_AS_PROPS
Entries can be accessed as properties (read and write).
Table of Contents
User Contributed Notes 7 notes
// How many items are we iterating over?
// The good thing here is that it can be iterated with foreach loop
/* Outputs something like */
Need a callback on an iterated value, but don’t have PHP 5.4+? This makes is stupid easy:
and to iterate recursively use the (sparsely documented) RecursiveArrayIterator
?>
Output
———
apple:yummy
orange:ah ya, nice
grape:wow, I love it!
plum:nah, not me
potato:chips
carrot:soup
I recommend using ArrayIterator() only in the IteratorAggregate interface on behalf of memory usage.
When not used in that context, the array will be copied on creating a new ArrayIterator().
$data1 = new Data ();
echo memory_get_usage (), PHP_EOL ;
// 4610240
Unsetting all keys of an ArrayItem within foreach will always leave the second key:
// ArrayIterator Object
// (
// [storage:ArrayIterator:private] => Array
// (
// [1] => 1
// )
// )
?>
I’m not sure if this is a bug as unsetting keys within foreach is usually a bad idea to begin with (use while instead), but it’s something to be aware of.