Php foreach and list

Php foreach and list

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())

Читайте также:  Css page header and footer

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.

Источник

Using list() with foreach() in PHP

Continuing my showcasing of all of the awesomeness in PHP 5.5 that I am discovering since my upgrade from 5.3, let’s discuss using the the list() function inside of a foreach() block.

Have you ever had a situation where you are looping through a multi-dimensional array and the array is non-associative? If so, you probably have some code that looks like this:

$items = array( array('var1', 'var2', 'var3'), array('var1', 'var2', 'var3'), array('var1', 'var2', 'var3'), array('var1', 'var2', 'var3'), array('var1', 'var2', 'var3'), ); foreach ($items as $item)  list($var1, $var2, $var3) = $item; if ($var1 == $var2)  echo $var3; > > 

Or even worse, you’re not even using the list() function:

foreach ($items as $item)  $var1 = $item[0]; $var2 = $item[1]; $var3 = $item[3]; if ($var1 == $var2)  echo $var3; > > 

Or worse than that, lacking any sort of variable mapping / meaningful references to the variables:

foreach ($items as $item)  if ($item[0] == $item[1])  echo $item[2]; > > 

NO LONGER! as now you can leverage the assignment power of list() right inside of your foreach() statement:

foreach ($items as list($var1, $var2, $var3))  if ($var1 == $var2)  echo $var3; > > 

I haven’t run any benchmarks to see if this is any faster or slower than using list() inside of the block itself instead of in the statement, but to me it’s worth a small bit of overhead for the cleanliness of the code when dealing with a small number of arguments.

What’s your preferred method? Comment below!

Good stuff? Want more?

100% Fresh, Grade A Content, Never Spam.

About Josh

Husband. Father. Pug dad. Musician. Founder of Holiday API, Head of Engineering and Emoji Specialist at Mailshake, and author of the best damn Lorem Ipsum Library for PHP.

Источник

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 ); // разорвать ссылку на последний элемент
?>

Указатель на $value возможен, только если на перебираемый массив можно ссылаться (т.е. если он является переменной). Следующий код не будет работать:

Ссылка $value на последний элемент массива остается даже после того, как оператор foreach завершил работу. Рекомендуется уничтожить ее с помощью функции unset() .

Замечание:

Оператор foreach не поддерживает возможность подавления сообщений об ошибках с помощью префикса ‘@’.

Вы могли заметить, что следующие конструкции функционально идентичны:

$arr = array( «one» , «two» , «three» );
reset ( $arr );
while (list(, $value ) = each ( $arr )) echo «Значение: $value
\n» ;
>

foreach ( $arr as $value ) echo «Значение: $value
\n» ;
>
?>

Следующие конструкции также функционально идентичны:

$arr = array( «one» , «two» , «three» );
reset ( $arr );
while (list( $key , $value ) = each ( $arr )) echo «Ключ: $key ; Значение: $value
\n» ;
>

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:

Источник

Оцените статью