Backend Development 14 min read

Understanding PHP 7.4 zval and zend_string Internals with GDB Debugging

This tutorial walks through PHP 7.4’s internal zend_string and zval structures, explains their role in binary‑safe strings and copy‑on‑write memory management, and demonstrates step‑by‑step debugging with GDB to inspect variable states and reference counts.

php中文网 Courses
php中文网 Courses
php中文网 Courses
Understanding PHP 7.4 zval and zend_string Internals with GDB Debugging

The article examines the internal data structures of PHP 7.4, focusing on zend_string and zval , and shows how they provide binary‑safe strings and enable copy‑on‑write (COW) memory optimisation.

The zend_string definition is presented:

<code>struct _zend_string {
    zend_refcounted_h gc; // reference count and type info (8 bytes)
    zend_ulong        h;   // hash value (8 bytes)
    size_t            len; // string length (8 bytes)
    char              val[1]; // flexible array for the string data
};</code>

The accompanying zend_refcounted_h struct stores the reference count and a type flag:

<code>typedef struct _zend_refcounted_h {
    uint32_t refcount; // reference count
    union {
        uint32_t type_info; // variable category
    } u;
} zend_refcounted_h;</code>

Copy‑on‑write is highlighted as a technique widely used in Redis, the Linux kernel, and PHP itself. In PHP 7, assigning a string does not duplicate the data; instead, the refcount in the embedded zend_refcounted_h is incremented, and it is decremented when the string is destroyed.

The article also explains the gc.u.flags field of zend_string , which uses eight bits to tag a string with up to eight categories (e.g., persistent, interned, permanent).

Next, the zval structure is introduced, showing how the type and type_flags fields classify variables:

<code>struct _zval_struct {
    zend_value        value; // variable value (union)
    union {
        struct {
            ZEND_ENDIAN_LOHI_3(
                zend_uchar type,        // variable type
                zend_uchar type_flags, // classification flags
                union { uint16_t extra; } u)
        } v;
        uint32_t type_info; // variable type info
    } u1;
    // ... other fields omitted for brevity
};</code>

The type constants are listed (e.g., IS_STRING = 6 , IS_LONG = 4 ), demonstrating how a zval holding a string has type = IS_STRING and its value stored in the str member of the union.

To explore these structures in practice, the article guides the reader through using GDB to debug PHP. It shows how to install the necessary debuginfo packages, set a breakpoint at ZEND_ECHO_SPEC_CV_HANDLER , and step through the execution of a simple PHP script:

<code>&lt;?php
   $a="abcdefg";
   echo $a;
   $b=88;
   echo $b;
   $c = $a;
   echo $c;
   echo $a;
   $c ="abc";
   echo $c;
   echo $a;
</code>

GDB commands such as b ZEND_ECHO_SPEC_CV_HANDLER , r php7-4-test-zval.php , p z , and p *z are used to inspect the zval pointer, its fields, and the underlying zend_string data. The output confirms the reference count, hash, length, and actual string content.

Further inspection shows how the type field changes when the variable holds an integer ( IS_LONG = 4 ), illustrating the COW behaviour when the same string is assigned to another variable.

The tutorial concludes by encouraging readers to repeat the GDB walkthrough, deepen their understanding of PHP’s memory management, and continue exploring copy‑on‑write mechanisms in subsequent articles.

backenddebuggingPHPGDBcopy-on-writezvalzend_string
php中文网 Courses
Written by

php中文网 Courses

php中文网's platform for the latest courses and technical articles, helping PHP learners advance quickly.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.