📜 ⬆️ ⬇️

How are the variables in PHP

It seems like a simple question, it's not even clear what to answer, right?
We all know how to create a variable, how to get the value of a variable, how to take a reference to a variable in the end.
But how do they work from the inside?
What happens in the interpreter when you change the value of a variable? Or when you delete it?
How are the types of variables implemented?

In this article I will try to reveal exactly these topics.

Abstract

Variables in PHP are expressed in the form of some containers that store the type of the variable, the value, the number of referencing variables for this container, and the flag - is this variable referential.


')
Retreat about structures and pointers

If you have never written in C, you may not know about such things as structures and pointers that are used very widely here and without which it would probably be very difficult to imagine at least some complicated C program.
Structures are very similar to classes, only they cannot have methods, only data, pointers to data, and pointers to functions. By declaring a structure in C, you define the data type, and now when defining a variable, you can write the name of this structure in place of the type of that variable, like this:
my_super_struct super_struct_instance; 

Pointers are like reference variables, only their value is an address in memory. Actually, these are links like pointers, only they behave like de-referenced pointers. Better to show on the code:
 //   foo,       int int *foo; //    int int bar = 3; //     bar    . //  foo    ,    bar foo = &bar; //       (    ) //    (*foo)++; //      ,     //        foo++; 



Containers

The container is a structure called zval, it looks like this:
 struct zval { zvalue_value value; zend_uchar type; //  ,    char zend_uchar is_ref; zend_ushort refcount; }; 

As we see, there is a value, a type, a flag and the number of referencing variables.
There are such types as:

zvalue_value is a union. Union is a type in which you can declare several members of different types, but only one will be used in the end, here’s how it will be defied:
 typedef union _zvalue_value { long lval; // integer double dval; // float struct { char *val; int len; } str; // string HashTable *ht; // array zend_object obj; // object } zvalue_value; 

As a result, when you create a variable of this type, it will take in memory as much as it takes the heaviest element of the union.


Why so much extra?

Now let's look at - why is there, for example, some kind of refcount?
It's very simple: when you assign a variable to another variable, they both refer to the same zval, and the refcount is incremented.

(original with a dog here )

Now, if you want to change the value of one of these variables, then PHP, seeing a refcount greater than 1, will copy this zval, make the changes there, and your variable will already point to the new zval.
If it is a bit formalized, it will look something like this:
PhpUnder the hood
 $foo = "asd"; $bar = $foo; 
 bar,foo: { type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 2 } 
 $bar .= "q"; 
 foo: { type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 1 } bar: { type: string, value: str: val: "asdq" len: 4 is_ref: 0 refcount: 1 } 

This technique is called copy on write and it allows for a good reduction in memory consumption.
Also, the refcount is needed by the garbage collector, which removes from memory all zvals that have refcount = 0.

And what to do with the links and why is this is_ref?

And what happens to the links? It's very simple: if you create a link from a variable, then the is_ref flag becomes equal to 1, and the above optimization for this zval will not be applied anymore. I will explain the code:
PhpUnder the hood
 $foo = "asd"; $bar = $foo; 
 bar,foo: { type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 2 } 
 $zxc = &$foo; 
 zxc,foo: { type: string, value: str: val: "asd" len: 3 is_ref: 1 refcount: 2 } bar: { //  bar     zval type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 1 } 
 $qwe = $foo; 
 zxc,foo: { type: string, value: str: val: "asd" len: 3 is_ref: 1 refcount: 2 } bar: { type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 1 } qwe: { //        zval type: string, value: str: val: "asd" len: 3 is_ref: 0 refcount: 1 } 


Of course, if you take another link from foo, then the refcount zval, which is referenced by foo, will increase by one.

Perhaps on this (for now?) Everything, in the next part let's talk about arrays.

PS I don’t know how anyone will perceive these pictures, it seemed to me to be funny :) unfortunately I don’t have a scanner

Source: https://habr.com/ru/post/162713/


All Articles