Internal Implementation of Variables in PHP 7
In PHP, variables consist of two components: the variable name and variable value. These correspond to zval and zend_value structures respectively. PHP manages variabel memory through reference counting, which in PHP 7 is tracked in zend_value rather than zval.
Variable Definition and Initialization
PHP variables are defined using the $ keyword:
$varName;
$varName = "initial value";
These operations involve two distinct steps: declaration and initialization.
Core Data Structures
zval Structure
typedef struct _zval_struct zval;
typedef union _zend_value {
int64_t long_val; // Integer values
double double_val; // Floating-point values
zend_refcounted *ref_counted;
zend_string *string_ptr; // String references
zend_array *array_ptr; // Array references
zend_object *object_ptr; // Object references
zend_resource *resource_ptr; // Resource handles
zend_reference *reference_ptr;// Reference types
zend_ast_ref *ast_ref;
zval *zval_ptr;
void *void_ptr;
zend_class_entry *class_entry;
zend_function *function_ptr;
struct {
uint32_t word1;
uint32_t word2;
} double_word;
} zend_value;
struct _zval_struct {
zend_value stored_value;
union {
struct {
ZEND_ENDIAN_LOHI_4(
unsigned char type,
unsigned char type_flags,
unsigned char const_flags,
unsigned char reserved)
} detail;
uint32_t type_data;
} metadata;
union {
uint32_t variable_flags;
uint32_t hash_next;
uint32_t cached_slot;
uint32_t line_number;
uint32_t argument_count;
uint32_t foreach_position;
uint32_t foreach_index;
} auxiliary;
};
Data Type Constants
#define IS_UNDEFINED 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
#define IS_CONSTANT 11
#define IS_CONSTANT_AST 12
#define _IS_BOOL 13
#define IS_CALLABLE 14
#define IS_INDIRECT 15
#define IS_POINTER 17
Scalar Types
Simple types including booleans, integers, doubles, and null values store their data directly within the zend_value union without additional memory allocations.
String Implementation
struct _zend_string {
zend_refcounted_h refcount_header;
uint64_t hash_value;
size_t length;
char content[1];
};
Strings are categorized into several types based on their allocation method and lifecycle characteristics.
Array Implementation
Arrays are implemented as ordered hash tables:
typedef struct _zend_array HashTable;
struct _zend_array {
zend_refcounted_h refcount_header;
union {
struct {
ZEND_ENDIAN_LOHI_4(
unsigned char flags,
unsigned char apply_count,
unsigned char iterator_count,
unsigned char reserved)
} detail;
uint32_t flags;
} metadata;
uint32_t table_mask;
Bucket *data_array;
uint32_t used_count;
uint32_t element_count;
uint32_t table_size;
uint32_t internal_pointer;
int64_t next_free_element;
dtor_func_t destructor_func;
};
Reference Implementation
References create a specialized structure:
struct _zend_reference {
zend_refcounted_h refcount_header;
zval referenced_value;
};
Example reference behavior:
$original = "data string";
$reference = &$original;
$copy = $reference;
Memory Management
PHP employs reference counting with copy-on-write semantics for efficient memory management.
Reference Counting Mechanism
typedef struct _zend_refcounted_h {
uint32_t reference_count;
union {
struct {
ZEND_ENDIAN_LOHI_3(
unsigned char type,
unsigned char flags,
uint16_t gc_data)
} detail;
uint32_t type_info;
} metadata;
} zend_refcounted_h;
Not all data types utilize reference counting. Scalar types and interned strings employ direct value copying.
Copy-on-Write Semantics
When multiple variables reference the same value, modifications trigger a copy operation:
$first = [1, 2, 3];
$second = $first;
$second[] = 4; // Triggers copy operation
Garbage Collection
PHP utilizes a tracing garbage collector for circular references:
$circular = [];
$circular[] = &$circular;
unset($circular); // Creates collectable garbage
The garbage collector identifies and cleans up circular references that cannot be freed through simple reference counting.