Php for each this
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 ArrayIterator ( O [] array) this .array = array;
>
public boolean hasNext () return index < array. length ;
>
public O next () if ( ! hasNext ())
throw new NoSuchElementException ( ‘at end of array’ );
return array[ index ++];
>
public void remove () throw new UnsupportedOperationException ( ‘remove() not supported in array’ );
>
>
?>
And here is the same in php (using the appropriate function) :
/**
* Since the array is not mutable, it should use an internal
* index over the number of elements for the previous/next
* validation.
*/
class ArrayIterator implements Iterator private $array ;
public function __construct ( $array ) if ( ! is_array ( $array ))
throw new IllegalArgumentException ( ‘argument 0 is not an array’ );
$this -> array = array;
$this -> rewind ();
>
public function valid () return current ( $this -> array ) !== false ;
// that’s the bad method (should use arrays_keys, + index)
>
public function key () return key ( $this -> array );
>
public function current () return current ( $this -> array );
>
public function next () if ( $this -> valid ())
throw new NoSuchElementException ( ‘at end of array’ );
next ( $this -> array );
>
public function previous () // fails if current() = first item of array
previous ( $this -> array );
>
public function rewind () reset ( $this -> array );
>
>
?>
The difference is notable : don’t expect next() to return something like in Java, instead use current(). This also means that you have to prefetch your collection to set the current() object. For instance, if you try to make a Directory iterator (like the one provided by PECL), rewind should invoke next() to set the first element and so on. (and the constructor should call rewind())
class ArrayIterable < O >implements Iterable < O > private final O [] array;
public ArrayIterable ( O [] array) this .array = array;
>
public Iterator < O >iterator () return new ArrayIterator (array);
>
>
?>
When using an Iterable, in Java 1.5, you may do such loops :
for ( String s : new ArrayIterable < String >(new String [] < "a" , "b" >)) .
>
?>
Which is the same as :
Iterator < String >it = new ArrayIterable < String >(new String [] < "a" , "b" >);
while ( it . hasNext ()) String s = it . next ();
.
>
?>
While in PHP it’s not the case :
foreach ( $iterator as $current ) .
>
?>
Is the same as :
for ( $iterator -> rewind (); $iterator -> valid (); $iterator -> next ()) $current = $iterator -> current ();
.
>
?>
(I think we may also use IteratorAggregate to do it like with Iterable).
Take that in mind if you come from Java.
I hope this explanation is not too long.
Php for each this
The foreach construct provides an easy way to iterate over arrays. foreach works only on arrays and objects, and will issue an error when you try to use it on a variable with a different data type or an uninitialized variable. There are two syntaxes:
foreach (iterable_expression as $value) statement foreach (iterable_expression as $key => $value) statement
The first form traverses the iterable given by iterable_expression . On each iteration, the value of the current element is assigned to $value .
The second form will additionally assign the current element’s key to the $key variable on each iteration.
Note that foreach does not modify the internal array pointer, which is used by functions such as current() and key() .
In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference.
$arr = array( 1 , 2 , 3 , 4 );
foreach ( $arr as & $value ) $value = $value * 2 ;
>
// $arr is now array(2, 4, 6, 8)
unset( $value ); // break the reference with the last element
?>?php
Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset() . Otherwise you will experience the following behavior:
// without an unset($value), $value is still a reference to the last item: $arr[3]
foreach ( $arr as $key => $value ) // $arr[3] will be updated with each value from $arr.
echo » < $key >=> < $value >» ;
print_r ( $arr );
>
// . until ultimately the second-to-last value is copied onto the last value
// output:
// 0 => 2 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 2 )
// 1 => 4 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 4 )
// 2 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 )
// 3 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 )
?>
It is possible to iterate a constant array’s value by reference:
Note:
foreach does not support the ability to suppress error messages using @ .
Some more examples to demonstrate usage:
/* foreach example 1: value only */
?php
foreach ( $a as $v ) echo «Current value of \$a: $v .\n» ;
>
/* foreach example 2: value (with its manual access notation printed for illustration) */
$i = 0 ; /* for illustrative purposes only */
foreach ( $a as $v ) echo «\$a[ $i ] => $v .\n» ;
$i ++;
>
/* foreach example 3: key and value */
$a = array(
«one» => 1 ,
«two» => 2 ,
«three» => 3 ,
«seventeen» => 17
);
foreach ( $a as $k => $v ) echo «\$a[ $k ] => $v .\n» ;
>
/* foreach example 4: multi-dimensional arrays */
$a = array();
$a [ 0 ][ 0 ] = «a» ;
$a [ 0 ][ 1 ] = «b» ;
$a [ 1 ][ 0 ] = «y» ;
$a [ 1 ][ 1 ] = «z» ;
foreach ( $a as $v1 ) foreach ( $v1 as $v2 ) echo » $v2 \n» ;
>
>
/* foreach example 5: dynamic arrays */
foreach (array( 1 , 2 , 3 , 4 , 5 ) as $v ) echo » $v \n» ;
>
?>
Unpacking nested arrays with list()
It is possible to iterate over an array of arrays and unpack the nested array into loop variables by providing a list() as the value.
foreach ( $array as list( $a , $b )) // $a contains the first element of the nested array,
// and $b contains the second element.
echo «A: $a ; B: $b \n» ;
>
?>
The above example will output:
You can provide fewer elements in the list() than there are in the nested array, in which case the leftover array values will be ignored:
foreach ( $array as list( $a )) // Note that there is no $b here.
echo » $a \n» ;
>
?>
The above example will output:
A notice will be generated if there aren’t enough array elements to fill the list() :
foreach ( $array as list( $a , $b , $c )) echo «A: $a ; B: $b ; C: $c \n» ;
>
?>
The above example will output:
Notice: Undefined offset: 2 in example.php on line 7 A: 1; B: 2; C: Notice: Undefined offset: 2 in example.php on line 7 A: 3; B: 4; C:
foreach
Конструкция foreach предоставляет простой способ перебора массивов. Foreach работает только с массивами и объектами, и будет генерировать ошибку при попытке использования с переменными других типов или неинициализированными переменными. Существует два вида синтаксиса:
foreach (array_expression as $value) statement foreach (array_expression as $key => $value) statement
Первый цикл перебирает массив, задаваемый с помощью array_expression. На каждой итерации значение текущего элемента присваивается переменной $value и внутренний указатель массива увеличивается на единицу (таким образом, на следующей итерации цикла работа будет происходить со следующим элементом).
Второй цикл будет дополнительно соотносить ключ текущего элемента с переменной $key на каждой итерации.
Замечание:
Когда оператор foreach начинает исполнение, внутренний указатель массива автоматически устанавливается на первый его элемент Это означает, что нет необходимости вызывать функцию reset() перед использованием цикла foreach.
Так как оператор foreach опирается на внутренний указатель массива, его изменение внутри цикла может привести к непредсказуемому поведению.
Для того, чтобы напрямую изменять элементы массива внутри цикла, переменной $value должен предшествовать знак &. В этом случае значение будет присвоено по ссылке.
$arr = array( 1 , 2 , 3 , 4 );
foreach ( $arr as & $value ) $value = $value * 2 ;
>
// массив $arr сейчас таков: array(2, 4, 6, 8)
unset( $value ); // разорвать ссылку на последний элемент
?>?php
Указатель на $value возможен, только если на перебираемый массив можно ссылаться (т.е. если он является переменной). Следующий код не будет работать:
Ссылка $value на последний элемент массива остается даже после того, как оператор foreach завершил работу. Рекомендуется уничтожить ее с помощью функции unset() .
Замечание:
Оператор foreach не поддерживает возможность подавления сообщений об ошибках с помощью префикса ‘@’.
Вы могли заметить, что следующие конструкции функционально идентичны:
$arr = array( «one» , «two» , «three» );
reset ( $arr );
while (list(, $value ) = each ( $arr )) echo «Значение: $value
\n» ;
>
?php
foreach ( $arr as $value ) echo «Значение: $value
\n» ;
>
?>
Следующие конструкции также функционально идентичны:
$arr = array( «one» , «two» , «three» );
reset ( $arr );
while (list( $key , $value ) = each ( $arr )) echo «Ключ: $key ; Значение: $value
\n» ;
>
?php
foreach ( $arr as $key => $value ) echo «Ключ: $key ; Значение: $value
\n» ;
>
?>
Вот еще несколько примеров, демонстрирующие использование оператора:
foreach ( $a as $v ) echo «Текущее значение переменной \$a: $v .\n» ;
>
/* Пример 2: значение (для иллюстрации массив выводится в виде значения с ключом) */
$i = 0 ; /* только для пояснения */
foreach ( $a as $v ) echo «\$a[ $i ] => $v .\n» ;
$i ++;
>
$a = array(
«one» => 1 ,
«two» => 2 ,
«three» => 3 ,
«seventeen» => 17
);
foreach ( $a as $k => $v ) echo «\$a[ $k ] => $v .\n» ;
>
/* Пример 4: многомерные массивы */
$a = array();
$a [ 0 ][ 0 ] = «a» ;
$a [ 0 ][ 1 ] = «b» ;
$a [ 1 ][ 0 ] = «y» ;
$a [ 1 ][ 1 ] = «z» ;
foreach ( $a as $v1 ) foreach ( $v1 as $v2 ) echo » $v2 \n» ;
>
>
/* Пример 5: динамические массивы */
foreach (array( 1 , 2 , 3 , 4 , 5 ) as $v ) echo » $v \n» ;
>
?>
Распаковка вложенных массивов с помощью list()
В PHP 5.5 была добавлена возможность обхода массива массивов с распаковкой вложенного массива в переменные цикла, передав list() в качестве значения.
foreach ( $array as list( $a , $b )) // $a содержит первый элемент вложенного массива,
// а $b содержит второй элемент.
echo «A: $a ; B: $b \n» ;
>
?>
Результат выполнения данного примера:
Можно передавать меньшее количество элементов в list() , чем находится во вложенном массиве, в этом случае оставшиеся значения массива будут проигнорированы:
foreach ( $array as list( $a )) // Обратите внимание на отсутствие $b.
echo » $a \n» ;
>
?>
Результат выполнения данного примера:
Если массив содержит недостаточно элементов для заполнения всех переменных из list() , то будет сгенерировано замечание об ошибке:
foreach ( $array as list( $a , $b , $c )) echo «A: $a ; B: $b ; C: $c \n» ;
>
?>
Результат выполнения данного примера:
Notice: Undefined offset: 2 in example.php on line 7 A: 1; B: 2; C: Notice: Undefined offset: 2 in example.php on line 7 A: 3; B: 4; C: