php foreach updates

0
377
php foreach
php foreach

php foreach construct provides the easiest way to iterate the array elements.

It works on array and objects both.

The foreach loop though iterates over an array of elements, the execution is simplified and finishes the loop in less time comparatively.

It allocates temporary memory for index iterations which makes the overall system to redundant its performance in terms of memory allocation.

FACTS YOU SHOULD KNOW ABOUT FOREACH LOOPS

Almost every programming language supports foreach loops, and PHP is included.

I bet you have heard of it often.

There’s nothing special about it but I think there are a few facts which you should be aware of. so it is important not to make mistakes when using them.

In today’s post I show you  facts that every developer should know about foreach loops.

KEY INT CASTING

PHP has some user friendly features that should help beginners and less experienced developers code more easily.

One of these is type juggling: the PHP interpreter automatically sets variable’s types depending on the context and on which operators are used.

This doesn’t mean that PHP doesn’t have types. Actually, each variable does have its own type, but it can change over time.

$a = 1 makes $a an integer, and $a = ‘1’ makes $a a string. In both cases, even if the type is different, a statement like $a = $a + 1 makes $a becomes an integer.

While type juggling can be convenient, it’s important to always consider the variable type we are dealing with, expecially when using strict comparison operators (like “===“).

Strict comparison operators are very useful because they can differentiate between values like 0, FALSE or NULL, while loose comparison operators (llike “==“) consider them equivalent.

lets see some facts here.

Inside foreach loops you can access every key/value pair of the array you are iterating, and sometimes you may need to compare the key with some other value.

Here’s the thing:

if, and only if, the key is a numeric literal, then it is automatically converted into an integer at the start of the loop.

so, strict comparing it to a string will always return FALSE.

Lets look at the examples below

/* We define a two-elements array. Note that the second key is a numeric literal string. */
$array = array(
   'first' => 'first element',
   '2' => 'second element'
);

/* Here is what happens */
foreach ($array as $key => $value)
{
   echo 'Key is: ' . $key . '<br>';
   echo 'Key type is: ' . gettype($key) . '<br>';
   
   /* Let's try a comparison */
   if ($key === '2')
   {
      echo 'Key is "2"!<br>';
   }
   else
   {
      echo 'Key is NOT "2"!<br>';
   }
}

The result will be:

Key is: first
Key type is: string
Key is NOT “2”!
Key is: 2
Key type is: integer
Key is NOT “2”!

As you can see in the result, while the second array key is actually a string (‘2’), it is automatically casted to an integer inside the loop because it is a numeric literal.

If we try to strict compare it to ‘2’, the expression returns false.

One remedy to this problem is to explicity cast the key to string at the beginning of each loop (on line 13):

/* We define a two-elements array. Note that the second key is a numeric literal string. */
$array = array(
   'first' => 'first element',
   '2' => 'second element'
);

/* Here is what happens */
foreach ($array as $key => $value)
{
   $key = strval($key);
   echo 'Key is: ' . $key . '<br>';
   echo 'Key type is: ' . gettype($key) . '<br>';
   
   /* Let's try a comparison */
   if ($key === '2')
   {
      echo 'Key is "2"!<br>';
   }
   else
   {
      echo 'Key is NOT "2"!<br>';
   }
}

The time result will be

Key is: first
Key type is: string
Key is NOT “2”!
Key is: 2
Key type is: string
Key is “2”!

Now the strict comparison between the second key and ‘2’ returns true, as we expect.

FOREACH VS FOR VS WHILE PERFORMANCE

When you need to iterate through an array, you can also use a while loop or a for loop instead of using foreach.

Which way is the best in terms of performance?

I ran a test with an array of 1 million items.

When using integer keys, it turns out that all three control structures run in about the same time (0.02 seconds on my test machine).

However, if we are dealing with associative arrays (i.e., arrays with string keys), the foreach loop is more than twice as fast as the other two control structures.

This is probably caused by the fact that while and for structures need to make use of auxiliary function to retrieve the array’s elements, like current() and next().

Foreach is usually the easiest way to iterate through arrays, and it turns out to be the fastest too, so it should be your preferred choice.

It’s worth mentioning, however, that in real life scenarios the performance difference will be almost negligible, unless you need to deal with really huge arrays (and in that case, you should probably fix your application first…).

Look at the code below

/* Set this to avoid memory errors */
ini_set('memory_limit','1024M');


$array = array();

/* Use this for creating a numeric array */
for ($i = 0; $i < 1000000; $i++)
{
   $array[$i] = $i;
}

/* Or use this for creating an associative array */
for ($i = 0; $i < 1000000; $i++)
{
   $array[$i] = strval($i) . 'string';
}

$count = count($array);
$start = microtime(TRUE);

/* Foreach loop, ok for both array types */
foreach ($array as $item)
{
   $var = $item;
}

/* For loop only for numeric arrays */
for ($i = 0; $i < $count; $i++)
{
   $var = $array[$i];
}

/* While loop only for numeric arrays */
$i = 0;
while ($i < $count)
{
   $var = $array[$i];
   $i++;
}

/* For loop for associative arrays */
for ($item = current($array); $item !== FALSE; $item = next($array))
{
   $var = $item;
}

/* While loop for associative arrays */
$item = current($array);
while ($item !== FALSE)
{
   $var = $item;
   $item = next($array);
}

$end = microtime(TRUE);
echo ($end - $start);

KEY => VALUE PERFORMANCE

PHP Foreach loops support both the $array as $value and the $array as $key => $value syntax.

The first one is also the fastest in terms of performance: in my test, using the second syntax resulted in a 50% longer execution time.

If you don’t need the keys you should probably stick with the first syntax.

Even so, the numbers are so small that it’s unluckily that you would notice any difference in real life scenarios, so don’t worry about it too much (on my test machine, the two tests ran in about 0.2 and 0.3 seconds, for a 10 millions elements array).

RESET() NEEDED?

Before PHP 7, foreach relied on the internal array pointer for looping, so it was a good idea to use reset() afterwards (and, before PHP 5, before starting the loop too).

This is not the case anymore with PHP 7, as foreach makes now use of its own internal pointer.

This saves us a few lines of code.

The example below shows that after the foreach loop the array’s internal pointer still points to the first element:

$array = array(1, 2, 3);

foreach ($array as $item)
{
   echo 'Item: ' . $item . '<br>';
}

/* Current item is still 1 */
echo 'Current item: ' . current($array); /* Outputs 1 */

VARIABLES OVERRIDE

It’s important to be aware that foreach loops do not have their own scope.

This means that variables defined outside the loop are also available inside it, and any variable declared inside the loop will continue to be accessible even after the loop ends.

This also applies to the $key => $value variables used in the foreach head.

See the following examples

$array = array(1, 2);

$value = 'my value';

foreach ($array as $key => $value)
{
   // do something
}

echo $value; /* Output is "2" */

After the loop, $value won’t contain ‘my value’ anymore but the value 2 instead, as it has been overwritten by the foreach assignment.

While I was searching for more insights on this problem, I found this interesting post that highlights another potential danger.

look at the examples

$array = array(1, 2, 3);

foreach ($array as $key => &$value)
{
   // do something
}

/* Everything ok here */
print_r($array);

foreach ($array as $key => $value)
{
   // do something
}

/* Something wrong! */
print_r($array);

The output from the two print_r() is:
Array
(
[0] => 1
[1] => 2
[2] => 3
)
Array
(
[0] => 1
[1] => 2
[2] => 2
)

After the second foreach loop, the last element inside the array has changed.

What happened?

In the first foreach we use the &$value syntax, so $value is set as a reference to each array’s element. In the last loop, $value is therefore equivalent to $array[2].

After the foreach ends, $value continues to be accessible (because foreach does not have its own scope).

When the second foreach starts, $value is still bound to the array’s last element, so in every loop both $value and $array[2] are overwritten.

This is what happens in more detail:

  • After the first foreach, $value points to $array[2].
  • Second foreach, first iteration: $array[2] is set with the first array element (so, $array[2] = 1).
  • Second foreach, second iteration: $array[2] is set with the second array element (so, $array[2] = 2).
  • Second foreach, third iteration: $array[2] is set with the third array element (i.e. itself, so $array[2] = 2).

That explains the result.

In order to avoid this problem, is always a good idea to unset any variable used in foreach loops, expecially when using references.

MODIFY AN ARRAY FROM INSIDE THE LOOP

If you are using foreach to iterate thorugh an array and you want to modify the array itself, there are two ways to do that.

The first one is to point to the array element you want to edit with the $array[$key] syntax (so you have to use the foreach $key => $value syntax in the foreach head).

The other way is to define $value as a reference and edit it directly.

See the two examples on how to do it:

$array = array(1, 2);

foreach ($array as $key => $value)
{
   $array[$key] += 1;
}

print_r($array);
<?php

$array = array(1, 2);

foreach ($array as $key => &$value)
{
   $value += 1;
}

print_r($array);

In both cases the output will be:
Array
(
[0] => 2
[1] => 3
)

LEAVE A REPLY

Please enter your comment!
Please enter your name here