Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What does the PHP kernel do when the variable changes

2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article focuses on "what does the PHP kernel do when variables change". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn what the PHP kernel does when variables change.

Before you look at the following, let's first understand the structure of zval.

Typedef struct _ zval_struct {zvalue_value value; zend_uint refcount; zend_uchar type; zend_uchar is_ref;} zval

There are four elements in the zval structure. Value is a union that is used to actually store the value of zval. Refcount is used to count how many variables the zval is used. Type represents the data type stored by zval. Is_ref is used to indicate whether the zval is referenced.

Reference count

Let's analyze the above code:

$a = 'Hello World'; first this code is executed, and the kernel creates a variable and allocates 12 bytes of memory to store the string' Hello World' and the NULL at the end.

$b = $a; then execute this code, and what happens in the kernel when you execute this sentence?

Add 1 to the refcount in the zval pointed to by $a.

Point the variable $b to the zval that $a points to.

It looks something like this in the kernel, where active_symbol_table is the current variable symbol table

{

Zval * helloval

MAKE_STD_ZVAL (helloval)

ZVAL_STRING (helloval, "Hello World", 1)

Zend_hash_add (EG (active_symbol_table), "a", sizeof ("a")

& helloval, sizeof (zval*), NULL)

ZVAL_ADDREF (helloval)

Zend_hash_add (EG (active_symbol_table), "b", sizeof ("b")

& helloval, sizeof (zval*), NULL)

}

Unset ($a); after this code is executed, the kernel reduces the refcount count in the corresponding zval structure of a by one, and b remains the same as before

Copy while writing

After the execution of the above code, it is generally expected that $axi1 is not valid 6, but if, as with reference counting, $an and $b point to the same zval, isn't $a changed after changing $b?

How exactly is this achieved? let's take a look at it together:

A = 1; the kernel creates a zval and allocates 4 bytes to store the number 1.

B = $a; this step is the same as the second step in the reference count, pointing $b to the same zval as $an and incrementing the reference count value refcount in zval by 1.

B + = 5; the key is this step, what happens in this step, and how to ensure that the modification does not affect $a.

In fact, the Zend kernel will perform get_var_and_separete operations before changing zval. If recfount > 1, you need to detach and create a new zval to return. Otherwise, directly return the zval pointed to by the variable. Let's see how to separate to generate a new zval.

Copy a zval that is the same as the zval pointed to by $b.

Subtract 1 from the refcount count in the zval pointed to by $b.

Initialize the generated new zval and set the refcount=1,is_ref=0.

Let $b point to the newly generated zval.

Operate on the newly generated zval, which is copy-on-write.

Let's take a look at the main code when detached in the kernel:

Zval * get_var_and_separate (char * varname, int varname_len TSRMLS_DC)

{

Zval * * varval, * varcopy

If (zend_hash_find (EG (active_symbol_table))

Varname, varname_len + 1, (void**) & varval) = = FAILURE) {

/ * Variable doesn't actually exist fail out * /

Return NULL

}

If ((* varval)-> is_ref | | (* varval)-> refcount

< 2) { /* varname is the only actual reference, * or it's a full reference to other variables * either way: no separating to be done */ return *varval; } /* Otherwise, make a copy of the zval* value */ MAKE_STD_ZVAL(varcopy); varcopy = *varval; /* Duplicate any allocated structures within the zval* */ zval_copy_ctor(varcopy); /* Remove the old version of varname * This will decrease the refcount of varval in the process */ zend_hash_del(EG(active_symbol_table), varname, varname_len + 1); /* Initialize the reference count of the * newly created value and attach it to * the varname variable */ varcopy->

Refcount = 1

Varcopy- > is_ref = 0

Zend_hash_add (EG (active_symbol_table), varname, varname_len + 1

& varcopy, sizeof (zval*), NULL)

/ * Return the new zval* * /

Return varcopy

}

Change when writing

After the above code is executed, it is generally expected to be: $a = $b = = 1. How does this come true?

$a = 1; this step is the same as the * step in copy when writing.

The kernel in this step points $b to the zval that $a points to, adds 1 to refcount in zval, and sets is_ref in zval to 1.

B + = 5; this step is the same as the third step in write-time replication, but what happens in the kernel is different.

When the kernel sees a change in $b, it also executes the get_var_and_separate function to see if it needs to be separated.

If (* varval)-> is_ref, the zval pointed to by $b will also be returned directly without separation to generate a new zval, regardless of whether the refcount of the zval is greater than 1.

At this point, change the value of $b, and the value of $a will change because they point to the same zval.

The problem of separation

Now that you're smart, you may have seen the problem. What if a zval structure has both refcount counts and is_ref references?

If this happens, if $a, $b, and $c point to the same zval structure, who is Zend going to listen to when making the change? In fact, this place will not point to the same zval.

If you change this form of assignment (that is, reference assignment) when writing to a zval with is_ref = 0 & & refcount > 1, Zend will separate the variables to the right of the equal sign into a new zval.

Initialize the zval, subtract 1 from the refcount of the previous zval, and add 1 to the variable to the left of the equal sign pointing to the new zval,refcount, is_ref=1. Look at the picture below.

The above is another case, in the case of is_ref = 1, when you try to do a simple refcount+1 operation, you will separate a new zval to the variable to the left of the equal sign and initialize it. Take a look at the picture below.

At this point, I believe you have a deeper understanding of what the PHP kernel does when variables change, so you might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report