PHP source code analysis-variable reference count and Write-time replication (Referencecounting & Copy-on-Write)

Source: Internet
Author: User
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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.