Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP 7 changes to foreach: Can I still delete items in they array on which I'm iterating?

Tags:

php

php-7

The PHP 7 Backward-Incompatible Changes Document says the following about foreach:

When used in the default by-value mode, foreach will now operate on a copy of the array being iterated rather than the array itself. This means that changes to the array made during iteration will not affect the values that are iterated.

I'm trying to understand what this means, and my main question is whether this code will work the same in PHP 7 as it does in PHP 5.6?

foreach($array as $elementKey => $element) {     if ($element == 'x') {         unset($array[$elementKey]);     } } 

My two questions are:

  1. Will this code still work?

  2. If so, can you explain (maybe by example) what this new change in PHP 7 means?

Edit

I've been re-reading the doc statement. I'm thinking that what it means is that, if you change values of items lower down in the array, those changes won't be there when you get to those items in the iteration. Example:

$array = ['x', 'y', 'z'];  $new = [];  foreach($array as $element) {     if ($element == 'x') {         $array[2] = 'a';     }      $new[] = $element; }  print_r($new); 

However, when I run this example it doesn't seem to show any difference in PHP versions (although I've never used this tool before, so I'm not sure how it works).

I realize that if I do it by reference, I'll get an a in new. Otherwise I won't. But this seems to be the case in both versions.

What I really need to know is what is the incompatibility (by example)?

Edit 2

The answer link suggested by @NikiC provides the rest of the story I was looking for:

In most cases this change is transparent and has no other effect than better performance. However there is one occasion where it results in different behavior, namely the case where the array was a reference beforehand:

$array = [1, 2, 3, 4, 5]; $ref = &$array; foreach ($array as $val) {     var_dump($val);     $array[2] = 0; } /* Old output: 1, 2, 0, 4, 5 */ /* New output: 1, 2, 3, 4, 5 */ 

Previously by-value iteration of reference-arrays was special cases. In this case no duplication occurred, so all modifications of the array during iteration would be reflected by the loop. In PHP 7 this special case is gone: A by-value iteration of an array will always keep working on the original elements, disregarding any modifications during the loop.

This answer explains the rare "special case" where things work different between versions in regarding foreach operating on a copy of the array.

like image 363
userlite Avatar asked Jan 03 '16 03:01

userlite


People also ask

How do I remove an array from a foreach loop?

Use unset() function to remove array elements in a foreach loop. The unset() function is an inbuilt function in PHP which is used to unset a specified variable. The behavior of this function depends on different things.

Can you break a foreach loop PHP?

To terminate the control from any loop we need to use break keyword. The break keyword is used to end the execution of current for, foreach, while, do-while or switch structure.

How does PHP foreach work?

PHP foreach loop is utilized for looping through the values of an array. It loops over the array, and each value for the fresh array element is assigned to value, and the array pointer is progressed by one to go the following element in the array.


1 Answers

All it means is that you now have to explicitly say you want to reference the array you're iterating now.

In your example code, however, you're referencing the root array anyways so it will work whether or not you pass by reference.

<?php $array = ['x', 'y', 'z'];  foreach($array as $elementKey => $element) {     if ($element=='x') {         unset($array[$elementKey]);     } }  var_dump($array); // lists 'y' and 'z' 

A better example. In this case, we're changing the value inside the foreach without a reference. As such, the local changes will be lost:

<?php $array = ['x', 'y', 'z'];  foreach($array as $element) {     if ($element=='x') {         $element = 'a';     } }  var_dump($array); // 'x', 'y', 'z' 

Vs by reference, where we declare the $element to be a reference to the array element:

<?php $array = ['x', 'y', 'z'];  foreach($array as &$element) {     if ($element=='x') {         $element = 'a';     } }  var_dump($array); // 'a', 'y', 'z' 

Here's a demo of this code running on various versions of PHP.

like image 132
Machavity Avatar answered Oct 16 '22 08:10

Machavity