Heim  >  Artikel  >  Backend-Entwicklung  >  Wie speichert PHP Variablen? Verstehen Sie die Zval-Struktur?

Wie speichert PHP Variablen? Verstehen Sie die Zval-Struktur?

藏色散人
藏色散人nach vorne
2022-05-26 09:47:254544Durchsuche

zval im PHP-Quellcode

Beim Definieren einer Variablen in PHP ist es nicht erforderlich, einen Typ zu deklarieren. Zunächst wird der Variablen $a ein ganzzahliger Wert zugewiesen, der später problemlos in andere Typen geändert werden kann. Wie wird diese Variable $a im PHP-Quellcode gespeichert? Mit dieser Frage im Hinterkopf werfen wir einen Blick auf den Quellcode von PHP.

Der Quellcode von PHP ist in C geschrieben. Im PHP-Quellcode wird eine Zval-Struktur verwendet, um im PHP-Code erstellte Variablen zu speichern. Nehmen wir die Definition der zval-Struktur heraus und analysieren sie kurz.

Dies ist das offizielle PHP-Repository auf Github: github.com/php/php-src. Der in diesem Artikel verwendete Zweig ist PHP-7.4.29.

zval-Struktur

Finden Sie diese Datei im PHP-Quellcode: php-src/Zend/zend_types.h Sie können sehen, dass die zval-Struktur wie folgt definiert ist, mit dem Quellcode auf der linken Seite. Der Quellcode verwendet PHPs eigene definierte Typen zend_uchar, uint16_t, uint32_t usw. Diese Typen werden unter verschiedenen Plattformen und Compilern für die Plattform in char short int usw. konvertiert. Zum besseren Verständnis habe ich es in einen allgemeinen Typ übersetzt und auf der rechten Seite des Quellcodes angezeigt. Gleichzeitig wird auch die Makrofunktion ZEND_ENDIAN_LOHI_3() erweitert.

typedef struct _zval_struct zval;
...
       《源代码》                                               《翻译后》
-------------------------------------------------------------------------------------------
struct _zval_struct {                               | struct _zval_struct {
    zend_value value;                               |     zend_value value;
    union {                                         |     union {
        struct {                                    |         struct {
            ZEND_ENDIAN_LOHI_3(                     |             unsigned char type;
                zend_uchar type,                    |             unsigned char type_flags;
                zend_uchar type_flags,              |             union {
                union {                             |                 unsigned short extra;
                    uint16_t extra;                 |             } u;
                } u                                 |         } v;
            )                                       |         unsigned int type_info;
        } v;                                        |     } u1;
        uint32_t type_info;                         |     union {
    } u1;                                           |         unsigned int next;
    union {                                         |         unsigned int cache_slot;
        uint32_t next;                              |         unsigned int opline_num;
        uint32_t cache_slot;                        |         unsigned int lineno;
        uint32_t opline_num;                        |         unsigned int num_args;
        uint32_t lineno;                            |         unsigned int fe_pos;
        uint32_t num_args;                          |         unsigned int fe_iter_idx;
        uint32_t fe_pos;                            |         unsigned int access_flags;
        uint32_t fe_iter_idx;                       |         unsigned int property_guard;
        uint32_t access_flags;                      |         unsigned int constant_flags;
        uint32_t property_guard;                    |         unsigned int extra;
        uint32_t constant_flags;                    |     } u2;
        uint32_t extra;                             | };
    } u2;                                           |
};                                                  |

In der zval-Struktur wird der Wert der Variablen im Wertattribut des Typs zend_value gespeichert. Und verwenden Sie u1.v.type, um den Typ dieses Werts aufzuzeichnen. IS_LONG entspricht beispielsweise dem Ganzzahltyp und IS_STRING entspricht dem Zeichenfolgentyp.

zend_value Union

zend_value Typ ist auch in php-src/Zend/zend_types.h definiert. Es folgt die Definition von zend_value Union, und der Quellcode befindet sich auf der linken Seite. Außerdem habe ich auf der rechten Seite eine einfache Übersetzung vorgenommen und zend_long uint32_t zur einfacheren Anzeige in einen allgemeinen Typ übersetzt.

            《源代码》                                              《翻译后》
------------------------------------------------------------------------------------
typedef union _zend_value {                         | typedef union _zend_value {
    zend_long         lval; /* long value */        |     long              lval;
    double            dval; /* double value */      |     double            dval;
    zend_refcounted  *counted;                      |     zend_refcounted  *counted;
    zend_string      *str;                          |     zend_string      *str;
    zend_array       *arr;                          |     zend_array       *arr;
    zend_object      *obj;                          |     zend_object      *obj;
    zend_resource    *res;                          |     zend_resource    *res;
    zend_reference   *ref;                          |     zend_reference   *ref;
    zend_ast_ref     *ast;                          |     zend_ast_ref     *ast;
    zval             *zv;                           |     zval             *zv;
    void             *ptr;                          |     void             *ptr;
    zend_class_entry *ce;                           |     zend_class_entry *ce;
    zend_function    *func;                         |     zend_function    *func;
    struct {                                        |     struct {
        uint32_t w1;                                |         unsigned int w1;
        uint32_t w2;                                |         unsigned int w2;
    } ww;                                           |     } ww;
} zend_value;                                       | } zend_value;

Ein Merkmal der Union ist, dass der Speicher, den sie belegt, der Länge entspricht, die dem größten Typ in seinen Attributen entspricht. Unter diesen ist zend_long vom Typ long. Sie können sehen, dass die Länge von lval vom Typ long und dval vom Typ double jeweils 8 Byte beträgt. Andere Zeigertypen im Inneren sind ebenfalls 8 Bytes groß. Das letzte Strukturattribut ww besteht aus zwei int-Typen und die kombinierte Länge beträgt ebenfalls 8 Byte. Die Länge dieser Union beträgt daher 8 Byte.

In dem von uns geschriebenen PHP-Code werden die Werte von Ganzzahl- und Gleitkommadaten direkt in lval und dval gespeichert. Wenn es sich um eine Zeichenfolge, ein Array oder einen anderen Typ handelt, wird ein Speicherplatz zum Speichern der Daten zugewiesen und seine Adresse wird in zend_value gespeichert, dem zval.value-Attribut, z. B.: zval.value.zend_long = 9527, zval .value.zend_string = Zeichen-String-Adresse, zval.value.zend_array = Array-Adresse. Markieren Sie dann auf zval.u1.v.type, dass dieser zval.value eine Ganzzahl, ein Gleitkomma, eine Zeichenfolge oder ein anderer Typ ist. Die Typdefinition

zval.u1.v.type befindet sich auch in der Datei php-src/Zend/zend_types.h. Alle Definitionen lauten wie folgt:

/* regular data types */
#define IS_UNDEF        0
#define IS_NULL         1
#define IS_FALSE        2
#define IS_TRUE         3
#define IS_LONG         4
#define IS_DOUBLE       5
#define IS_STRING       6
#define IS_ARRAY        7
#define IS_OBJECT       8
#define IS_RESOURCE     9
#define IS_REFERENCE    10
/* constant expressions */
#define IS_CONSTANT_AST 11
/* internal types */
#define IS_INDIRECT     13
#define IS_PTR          14
#define IS_ALIAS_PTR    15
#define _IS_ERROR       15
/* fake types used only for type hinting (Z_TYPE(zv) can not use them) */
#define _IS_BOOL        16
#define IS_CALLABLE     17
#define IS_ITERABLE     18
#define IS_VOID         19
#define _IS_NUMBER      20

zval-Strukturspeichernutzung

Als nächstes analysieren wir, was zval benötigt Speicher belegt.

  • Wert: zend_value Typ 8 Bytes.

  • u1:

  • u1.v.type: unsigned char 1 Byte, u1.v.type_flags: unsigned char 1 Byte, u1.v.u: Es gibt nur einen unsigned short in der Union Das zusätzliche Attribut beträgt 2 Bytes, daher beträgt die Struktur von u1.v insgesamt 4 Bytes.

  • u1.type_info: unsigned int 4 Bytes.

  • Die Länge der Union u1 ist also die Länge des längsten Attributs: 4 Bytes.

  • u2: Es ist auch eine Union, die Attribute vom Typ int enthält, daher beträgt die Länge 4 Bytes.

  • Der von zval belegte Gesamtspeicher beträgt also 8 + 4 + 4 = 16 Bytes.

Das heißt, wenn wir PHP-Code schreiben und eine ganzzahlige Variable erstellen, belegt diese während des Betriebs tatsächlich 16 Byte Speicher, und der Speicheraufwand ist mindestens doppelt so hoch wie der der C-Sprache. Dieser doppelte Overhead bringt natürlich auch die Flexibilität von PHP im Umgang mit Variablen mit sich.

Empfohlenes Lernen: „PHP-Video-Tutorial

Das obige ist der detaillierte Inhalt vonWie speichert PHP Variablen? Verstehen Sie die Zval-Struktur?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:learnku.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen