PHP syntax has two assignment modes: reference assignment and non-reference assignment. & Lt ;? Php $ a1; $ B $ a; // non-reference assignment $ c & amp; $ B; // reference assignment & lt ;? Php $ a1; $ B $ a; // non-reference assignment $ c & amp; $ B; // reference assignment from the surface... Sy
PHP syntax has two assignment modes: reference assignment and non-reference assignment.
$ A = 1;
$ B = $ a; // non-reference value assignment
$ C = & $ B; // value assignment
$ A = 1;
$ B = $ a; // non-reference value assignment
$ C = & $ B; // value assignment
On the surface, we usually think like this: "The reference value assignment is that two variables correspond to the same variable (in C, it is actually a zval ), if the value is not referenced, a new variable (zval) is generated directly, and the value is copied ".
In most cases, this can be figured out. (#1)
But in some cases, it may seem very inefficient, for example: (#2)
Function print_arr ($ arr) {// non-reference transfer
Print_r ($ arr );
}
$ Test_arr = array (
'A' => 'A ',
'B' => 'B ',
'C' => 'C ',
...
); // A large array
Print_arr ($ test_arr); // The first time the print_arr function is called, the output is executed.
Print_arr ($ test_arr); // The second call to the print_arr function to execute the output
Function print_arr ($ arr) {// non-reference transfer
Print_r ($ arr );
}
$ Test_arr = array (
'A' => 'A ',
'B' => 'B ',
'C' => 'C ',
...
); // A large array
Print_arr ($ test_arr); // The first time the print_arr function is called, the output is executed.
Print_arr ($ test_arr); // The second call to the print_arr function to execute the output
If you follow the above understanding (#1), execute print_arr twice and use the non-reference method, two new variables identical to $ test_arr will be generated, it will be very inefficient.
The actual code is running, and no two new variables are generated. Because the PHP kernel has helped us to optimize it.
How to implement it? Here we will talk about the key points of this article: Reference counting & Copy-on-Write, which is optimized using the Reference counting and Write-time replication mechanisms.
Before introducing these two mechanisms, you should first understand the basic knowledge: how variables in PHP are expressed in the kernel.
All variables defined in PHP are represented by a zval. the zval definition is defined in Zend/zend. h:
Typedef struct _ zval_struct zval;
Typedef union _ zvalue_value {
Long lval;/* long value */
Double dval;/* double value */
Struct {
Char * val;
Int len;
} Str;
HashTable * ht;/* hash table value */
Zend_object_value obj;
} Zvalue_value;
Struct _ zval_struct {
/* Variable information */
Zvalue_value value;/* value */
Zend_uint refcount;
Zend_uchar type;/* active type */
Zend_uchar is_ref;
};
Typedef struct _ zval_struct zval;
Typedef union _ zvalue_value {
Long lval;/* long value */
Double dval;/* double value */
Struct {
Char * val;
Int len;
} Str;
HashTable * ht;/* hash table value */
Zend_object_value obj;
} Zvalue_value;
Struct _ zval_struct {
/* Variable information */
Zvalue_value value;/* value */
Zend_uint refcount;
Zend_uchar type;/* active type */
Zend_uchar is_ref;
};
Refcount and is_ref are the basis for implementing the two mechanisms: reference count and write-time replication.
Refcount refers to the reference count of the current variable storage, which is 1 when zval is initially created. Refcount ++. Refcount --.
Is_ref indicates whether a zval is referenced. When zval is initialized, it will be 0, indicating that it is not a reference.
$ A; // a: refcount = 1, is_ref = 0, value = NULL;
$ A = 1; // a: refcount = 2, is_ref = 0, value = 1;
$ B = $ a; // a, B: refcount = 3, is_ref = 0, value = 1;
$ C = $ a; // a, B, c: refcount = 4, is_ref = 0, value = 1;
$ D = & $ c; // a, B: refcount = 3, is_ref = 0, value = 1; c, d: refcount = 1, is_ref = 1, value = 1
$ A; // a: refcount = 1, is_ref = 0, value = NULL;
$ A = 1; // a: refcount = 2, is_ref = 0, value = 1;
$ B = $ a; // a, B: refcount = 3, is_ref = 0, value = 1;
$ C = $ a; // a, B, c: refcount = 4, is_ref = 0, value = 1;
$ D = & $ c; // a, B: refcount = 3, is_ref = 0, value = 1; c, d: refcount = 1, is_ref = 1, value = 1 the comment in the above code indicates the refcount and is_ref changes after this line is executed.
Copy on Write
If the Php variable shares data through reference counting, what if it changes the value of one of the variables?
When Zend tries to write a variable, if zval pointed to by the variable is shared by multiple variables, it will copy a zval with ref_count as 1 and decrease the refcount of the original zval, this process is called "zval separation ". It can be seen that zend performs the copy operation only when a write operation occurs. Therefore, it is also called copy-on-write (copy at write time)
For referenced variables, the requirement is different from that for non-referenced variables. variables that reference values must be bundled. modifying a variable modifies all bound variables.
$ A = 1;
$ B = $;
$ A = 1;
$ B = $ a; memory structure during execution:
$ A = 1;
$ B = &;
$ A = 1;
$ B = & a; memory structure during execution:
As you can see from the above, whether it is a reference or a non-reference, this direct value assignment will not generate new variables.
When it is referenced, is_ref is set to 1. If it is not referenced, is_ref is set to 0.
Read/write replication separates variables according to is_ref.
When is_ref = 1 is used to reference a variable, execute "separated variables under reference"
$ A = 1;
$ B = $;
$ C = & $ B;
$ A = 1;
$ B = $;
$ C = & $ B; memory structure during execution:
When is_ref = 0 and it is a non-referenced variable, execute "variable separation under non-referenced"
$ A = 1;
$ B = & $;
$ C = $ B;
$ A = 1;
$ B = & $;
$ C = $ B;
Memory structure during execution:
Only when you need to change the value of a variable,
Looking back at the code (#2), we can see that no new variables are actually generated, and the variable $ test_arr is always output. Therefore, this is why the reference method is rarely used to pass variables in PHP, but there is still no performance problem.
From God's blog