Starting from the reference BUG of PHP

Source: Internet
Author: User
Tags what php
I am interested in this article because my colleagues sent this article about Copy-On-Write in PHP On TIPI to the group. Let's talk about this question as follows :? Php $ foo [love] 1; $ bar $ tipi $ foo; $ tipi [love] 2; echo $ foo [love]; Output 2 I believe many people will think this

I am interested in this article because my colleagues sent this article about Copy-On-Write in PHP On TIPI to the group. Let's talk about this question as follows :? Php $ foo ['love'] = 1; $ bar = $ tipi = $ foo; $ tipi ['love'] = '2 '; echo $ foo ['love']; // output 2 I believe many people think this

I am interested in this article because my colleagues sent this article about Copy-On-Write in PHP On TIPI to the group. Let's talk about this question as follows:

 

I believe many people think this is a BUG. Why is the value of $ foo ['love'] changed? In the official email list, this issue is also being discussed. It is not so much a feature as I would like to say it is a BUG. Because all actions that are likely to be pitted should be circumvented.

Why is there such a difference? Let's start from here.

Variable type:
There are eight types of PHP variables, of which NULL and resource are special types. We commonly use simple types: int, float, string, boolean, and composite types: array, object.
What is simple type? What is composite type? Let's take a look at how PHP implements variables.

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;typedef struct _zval_struct zval;struct _zval_struct {zvalue_value value;zend_uint refcount__gc;zend_uchar type;zend_uchar is_ref__gc;};

As above, zvalue_value and zval are defined in the consortium.
Zval is the structure of the variable, and zval_value is the value of zval.
In zval, type indicates the data type. They are:
#define IS_NULL0#define IS_LONG1#define IS_DOUBLE2#define IS_BOOL3#define IS_ARRAY4#define IS_OBJECT5#define IS_STRING6#define IS_RESOURCE7

3 (IS_BOOL) and the following types can be expressed through one of zvalue_value in the consortium. boolean and integer values are stored in lval, floating point and double-precision floating point are saved in double, and NULL does not need to be saved, you only need to set type to IS_NULL. The rest is troublesome. For example, if the string type exists in struct str, the string and length are saved separately. That is to say, we use strlen to directly return the length without re-calculating the string length. The array is saved in the hash table ht, and the object is saved in obj.
Compound variables, such as $ array ['foo'] = 888;, $ array is of the IS_ARRAY type, while $ array ['foo'] is of the IS_LONG type, in $ array, not 888 is actually saved, but a pointer to $ array ['foo. That is to say, the value of array is actually a collection of pointers.

Let's look at refcount _ gc and is_ref _ gc in zval. Refcount _ gc is a counter, while is_ref _ gc indicates whether the variable is referenced. So
$ A = & $ B; $ c = 1;
The is_ref _ gc values of $ a and $ B are both 1, and the is_ref _ gc value of $ c is 0.
So when will refcount _ gc be used? Let's talk about the variable recycling mechanism.
If a variable is canceled when it is unset, will the memory occupied by its value be immediately released? Actually not. The refcount _ gc counter is used for this purpose.
PHP has a feature called Copy-On-Write. For example:

$a = 1;$b = $a;

At this time, PHP does not apply for a new memory for $ B. Instead, it adds 1 to the refcount _ gc counter of $ a and then assigns $ a to $ B. When we echo $ B, we actually read the value that $ a points to the same memory address. When we execute:
$ B = 2;
PHP will first check if $ B is referenced (not here ), then, subtract 1 from the refcount _ gc of $ B and $ a and determine whether it is 0 (not here, but 1 ), then PHP will apply for a new memory for $ B, copy the value of $ a, and change it to 2. At this time, the refcount _ gc of $ B will change to 1.
So what PHP does in unset ($ B) is to judge whether its refcount _ gc value is 0 after the value of 1. If yes, in this case, it is recycled (the memory is not actually released, but only in the buffer zone. When it is full, it is released). If not, only $ B is deleted from the symbol table.

=================== Rest, take a break ========== one cut off ====================
Let's analyze why the question at the beginning of the article is shown in the following line:

$ Foo ['love'] = 1; // $ foo: refcount = 1; isref = 0; //-> love: refcount = 1; isref = 0; $ bar = & $ foo ['love']; // $ bar: refcount = 2; isref = 1; // $ foo-> love: refcount = 2; isref = 1; // $ foo: refcount = 1; isref = 0; $ tipi = $ foo; // $ foo: refcount = 2; isref = 0; // $ foo-> love: refcount = 2; isref = 1; // $ tipi: refcount = 2; isref = 0; // $ tipi-> love: refcount = 2; isref = 1; // note that the refcount of the composite type (array) $ foo in this step is automatically increased to 2, $ foo ['love'] is another memory address pointed to by the array's hashtable. It will not be copied $ tipi ['love'] = '2 '; // here $ tipi ['love'] is a reference, like $ foo ['love'] echo $ foo ['love']; // when $ tipi ['love'] is changed, 2 is output here.

Do you understand?
After reading this analysis, I believe you will think that this is a feature of PHP, and so do I. After knowing the truth, it seems that we have to overturn the previous conclusion-this is a BUG. But think about it, this kind of pitfall should not actually appear, so I still stick to the initial idea-this is a BUG! Of course.

Do not misuse references, because PHP has optimized the variables. But sometimes it should be used. For example, you actually want to transfer an address instead of a value.

In addition, the snake should remind you that the dynamic reference has been canceled in 5.4.0, for example:

function myfunc($var){    $var = 1;}myfunc(& $foo)

This method may cause errors. The correct usage should be:
function myfunc(& $var){    $var = 1;}myfunc($foo)

Okay, so here we are. Goodbye!

Original article address: Let's talk about the BUG reference in PHP. Thank you for sharing it with the original author.

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.