Home  >  Article  >  Backend Development  >  PHP kernel zval

PHP kernel zval

不言
不言Original
2018-04-19 09:26:152725browse

The main content of this article is about the zval of the PHP kernel, which has a certain reference value. Now I share it with everyone. Friends in need can refer to it

Original address
Author: Twei Home Page

Preface


During the previous interview, the interviewer asked how variables are implemented in PHP. Unfortunately, he only answered that it was probably implemented using a structure. This article was summarized quite well after Google, so I reprinted it and learned from it.

Text


Data types in PHP


Compared to other programming languages ​​such as C, C, Java, etc., PHP is A weakly typed language means that when we want to use a variable, we do not need to declare its type. This feature brings us a lot of convenience, but sometimes it also brings some pitfalls. So, does PHP really have no data types?

of course not. In the PHP official documentation, variables in PHP are divided into three categories: scalar types, complex types and special types. Scalar types include bool, int, float and string; complex types include arrays and objects; special types include NULL and resources . So in terms of PHP variable breakdown, there are 8 data types.

As we all know, the bottom layer of PHP is implemented in C language. Our PHP script will be parsed into C code by Zend engine and then executed. So, how is a PHP variable represented in C language? What will it eventually be parsed into?

The answer is zval. Regardless of the type of PHP variable, it is uniformly represented by a structure called zval in the PHP source code. zval can be seen as a container for PHP variables in C code. It stores the value, type and other related information of this variable.

Then let’s take a look at the basic structure of zval (requires some basic knowledge of C language).

The basic structure of zval


In the PHP source code, the structure of zval is a structure (struct) named _zval_struct , the specific definition is in the Zend/zend.h file of the source code. The following is an excerpt of the relevant code:

struct _zval_struct {
    zvalue_value value;       /* value */ 
    zend_uint refcount__gc;   /* value of ref count */
    zend_uchar type;          /* active type */ 
    zend_uchar is_ref__gc;    /* if it is a ref variable */ }; 
typedef struct _zval_struct zval;

In other words, in the source code of PHP, this structure is used The body represents various types of variables in PHP, and can also implement other functions, such as garbage collection (GC: Grabage Collection).

You can see that it consists of 4 fields, each representing certain information about this variable.

ZVALUE_VALUE VALUE


value is used to represent the actual value of the variable. Specifically, it is a union of zvalue_value:

typedef union _zvalue_value {    long lval;                  /* long value */
    double dval;                /* double value */
    struct {                    /* string */
        char *val;        int len;
    } str;
    HashTable *ht;              /* hash table value,used for array */
    zend_object_value obj;      /* object */} zvalue_value;

You can see There are only 5 fields in _zvalue_value, but there are 8 data types in PHP. So how to use 5 fields to represent 8 types?

This is a clever part of PHP design. It achieves the purpose of reducing fields by reusing fields. For example, within PHP, Boolean types, integers and resources (as long as the identifier of the resource is stored) are stored through the lval field; dval is used to store floating point types; str stores strings; ht stores arrays (note that in PHP The array is actually a hash table); and obj stores object types; if all fields are set to 0 or NULL, it means NULL in PHP, so that 5 fields are used to store 8 types of values.

ZEND_UINT REFCOUNT__GC


As you can see from its suffix gc, this field is related to garbage collection.

It is actually a counter to save how many variables point to the zval. When the variable is generated, it is set to 1, that is, refcount = 1.

Performing different operations on a variable will change its value. Typical assignment operations such as

b will increase refcount by 1, and the unset() operation will decrease 1 accordingly.

Garbage collection can be performed by judging its value. Before PHP5.3, the reference counting mechanism was used to implement GC: if the refcount of a zval is reduced to 0, then the Zend engine will think that there is no variable pointing to the zval and will release the memory space occupied by the zval. But just using the reference counting mechanism cannot release the zval of the circular reference, which will lead to a memory leak (Memory Leak).

Before 5.3, the name of this field was still called refcount. After 5.3, when a new garbage collection algorithm was introduced to deal with circular references, the author added a large number of macros to operate refcount, in order to make errors faster appeared, so it was renamed refcount__gc, forcing everyone to use macros to operate refcount.

Similarly, there is a fourth field is_ref. This value indicates whether a type in PHP is a reference.
If you want to know about PHP's garbage collection mechanism, you can refer to this blog: PHP's garbage collection mechanism
Note: Variables can also be called symbols, symbols. All symbols exist in the symbol table, and different scopes use different symbol tables. This blog explains this.

ZEND_UCHAR TYPE


这个字段用于表明变量属于 PHP 8 种类型的哪种。在 zend 内部,这些类型对应于下面的宏(代码位置 phpsrc/Zend/zend.h):

#define IS_NULL     0#define IS_LONG     1#define IS_DOUBLE   2#define IS_BOOL     3#define IS_ARRAY    4#define IS_OBJECT   5#define IS_STRING   6#define IS_RESOURCE 7#define IS_CONSTANT 8#define IS_CONSTANT_ARRAY   9#define IS_CALLABLE 10

ZEND_UCHAR IS_REF__GC


这个字段用于标记变量是否是引用变量。对于普通的变量,该值为 0,而对于引用型的变量,该值为 1。这个变量会影响 zval 的共享、分离等。它也和 PHP 的垃圾回收有关。

PHP7中的zval


上述的 zval 结构,随着时间的发展,暴露出许多问题,例如占用空间大(24 字节)、不支持拓展、 对象和引用效率差等,所以在 PHP7 的时候,对 zval 进行了较大的改变,现在它的结构是这样的:

struct _zval_struct {    union {
        zend_long         lval;             /* long value */
        double            dval;             /* double value */
        zend_refcounted  *counted;
        zend_string      *str;
        zend_array       *arr;
        zend_object      *obj;
        zend_resource    *res;
        zend_reference   *ref;
        zend_ast_ref     *ast;
        zval             *zv;        void             *ptr;
        zend_class_entry *ce;
        zend_function    *func;        struct {
            uint32_t w1;
            uint32_t w2;
        } ww;
    } value;    union {        struct {
            ZEND_ENDIAN_LOHI_4(
                zend_uchar    type,         /* active type */
                zend_uchar    type_flags,
                zend_uchar    const_flags,
                zend_uchar    reserved)     /* call info for EX(This) */
        } v;
        uint32_t type_info;
    } u1;    union {
        uint32_t     var_flags;
        uint32_t     next;                 /* hash collision chain */
        uint32_t     cache_slot;           /* literal cache slot */
        uint32_t     lineno;               /* line number (for ast nodes) */
        uint32_t     num_args;             /* arguments number for EX(This) */
        uint32_t     fe_pos;               /* foreach position */
        uint32_t     fe_iter_idx;          /* foreach iterator index */
    } u2;
};

虽然看起来变得好大,但其实仔细看,它的字段都是联合体,这个新的 zval 在 64 位环境下,只需要 16 个字节(2 个指针 size)。PHP7 中的 zval,已经变成了一个值指针,它要么保存着原始值,要么保存着指向一个保存原始值的指针。

这部分内容来自鸟哥的GitHub。

总结


  1. zval 是一种 C 语言实现的数据结构,功能是作为 PHP 变量的容器;

  2. 它保存了变量的各种信息(如类型和值),并为其他功能(如垃圾回收)提供支持;

  3. 在不同的 PHP 版本中,它的结构不同。PHP7 的 zval 占 16 个字节,PHP5 的要占 24 个字节。

参考


PHP内核探索之变量(1)变量的容器-Zval
PHP垃圾回收深入理解
深入理解PHP7之zval

相关推荐:

PHP内核之探究内存管理与缓存机制

PHP内核分析-Zend虚拟机详解

The above is the detailed content of PHP kernel zval. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:php-fpm static dynamicNext article:php-fpm static dynamic