There are three basic holes in PHP: foreach traversal, reference mechanism &, and array.

Today we’re talking about some of the oddities in Foreach.

Before explaining, you can take a look at my other related articles, which belong to the same big knowledge point and are helpful to understand.

What exactly happens internally when we use Foreach? (PHP5)

Copy-on-write (COW)

PHP low-level analysis: About forced splitting

△△△ Before writing: The following conclusions are based on the PHP5 version, because The Times are advancing, in PHP7 internal structure module and reference module have changed significantly, PHP7 foreach output rules also changed immediately. Of course, since PHP7 is still a year or two away from becoming ubiquitous (this year is 2016), there is some value in this article, which will at least give you an understanding of the PHP internals.

If you have any questions, feel free to post them in the comments and I’ll answer them.

This article is suitable for PHPer with some basic knowledge.

This is a screenshot from a talk given at Think 2015 PHP Tech Summit by Hui Xinchen, a member of the PHP7 core development team, and the only Chinese on the team. He is talking about the differences between PHP5 foreach and PHP7 foreach. Let’s take a look at the parts of his speech that refer to PHP5.

So let’s focus on the three code execution flows in this diagram.

Let me show you how three pieces of code work

code1.php

$value) { var_dump(current($a)); //output int(2) int(2) int(2) } ? >Copy the code

The output value is int(2) int(2) int(2).

Students may wonder how there are three ‘2s’ when at first glance there is no obvious copy-on-write or forced split.

The key is the current() function:

Foreach loop starts, copy an array, and refcount_gc=2. (PHP5))

The Pointers to both the original array ($a) and the copy array (I’ll call it $a_copy) point to subscript 1,

The argument to the current() operation must be a reference array (the red line), or is forced to be a reference array if it is not (i.e. is_ref__GC from 0 -> 1 in the structure).

According to the forced splitting principle, a structure’s URL “forced splitting” occurs when the value of IS_ref__gc goes from 0 -> 1 and the url” forced splitting “occurs when refcount_gc=2.

$a = $a; $a = $a; $a = $a

code2.php


Copy the code

This code is similar to code1.php, except that a reference assignment is made before foreach, and the structure changes to refcount_gc=2; is_ref_gc=1; Foreach then iterates through the array, at which point the Pointers to the original array ($a), the copy array (I’ll call it $a_copy), and $B all point to subscript 1 and are all responsible for references (is_ref_gc).

Var_dump (current($a)); The argument to the current() operation must be a reference array (red line). If it is not a reference array, it is forced to be a reference array (i.e. is_ref__GC from 0 -> 1 in the structure).

$a = $a; $a = $a; $a = $a; $a = $a;

code3.php

$value) { var_dump(current($a)); //output int(1) int(1) int(1) } ? >Copy the code

$b=$a; $b=$a; $b=$a; The reason for this is foreach’s mechanics:

Before the foreach loop, we need to determine the refcount of the array. If it is greater than 1, the array itself becomes a new structure, and the loop operates on the new structure.

Operation process: line:3; $a; $b; // Foreach starts the refcount check, copying the array is a new structure, foreach is the new structure. So when I go through the array, it doesn't matter what the array is. Line:5: // Prints the current unit of the array. Since the original and copied arrays are not one structure, the pointer to the original array is unchanged, and prints int(1).Copy the code

If there is still some confusion, you can read it several times. By the way, it is recommended to read these articles again. If you can understand foreach, it is almost enough to master it.

What exactly happens internally when we use Foreach? (PHP5)

Copy-on-write (COW)

PHP low-level analysis: About forced splitting