← Назад к вопросам

Как в PHP устроено хранение переменных?

3.0 Senior🔥 61 комментариев
#PHP Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Хранение переменных в PHP: механизм zval

В основе хранения переменных в PHP лежит структура zval (Zend value). Это внутренняя структура ядра Zend Engine, которая содержит информацию о типе данных, значении и дополнительных метаданных переменной.

Структура zval до и после PHP 7

До PHP 7 zval представлял собой структуру с несколькими полями:

struct _zval_struct {
    zvalue_value value;     // Значение переменной
    zend_uint refcount__gc; // Счетчик ссылок
    zend_uchar type;        // Тип данных
    zend_uchar is_ref__gc;  // Флаг ссылки
};

С PHP 7.0 произошла значительная оптимизация (проект phpng). Zval стал занимать 16 байт вместо 24 и изменил логику хранения:

struct _zval_struct {
    zend_value value;      // 8 байт
    union {
        struct {
            ZEND_ENDIAN_LOHI_4(
                zend_uchar type,         // Тип данных
                zend_uchar type_flags,   // Флаги типа
                zend_uchar const_flags,  // Константные флаги
                zend_uchar reserved)     // Зарезервировано
        } v;
        uint32_t type_info;              // Целочисленное представление
    } u1;
    union {
        uint32_t var_flags;
        uint32_t next;                 // Для хеш-таблиц
        uint32_t cache_slot;           // Кэш опкодов
        uint32_t lineno;               // Номер строки
        uint32_t num_args;             // Количество аргументов
        uint32_t fe_pos;               // Позиция в foreach
        uint32_t fe_iter_idx;          // Индекс итератора
    } u2;
};

Ключевые изменения в PHP 7+

  1. Счетчик ссылок и флаг is_ref перемещены в значение

    • Для типов, не являющихся ссылками, используется Copy-On-Write (COW)
    • Для ссылочных типов (объекты, ресурсы) счетчик ссылок хранится в самом значении
  2. Оптимизация для встроенных типов

    $a = 42;          // Целое число хранится непосредственно в zval
    $b = 3.14;        // Дробное число также хранится напрямую
    $c = "hello";     // Короткие строки (<16 байт) хранятся в zval
    $d = "long string..."; // Длинные строки хранятся отдельно
    

Типы данных и их хранение

PHP использует динамическую типизацию, и zval может содержать различные типы:

#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_REFERENCE 8
#define IS_CALLABLE 9

Механизм Copy-On-Write (COW)

COW - ключевая оптимизация для управления памятью:

$a = "original string";  // Создается zval со строкой
$b = $a;                 // Копируется только ссылка, не данные
$b[0] = 'O';            // Только здесь происходит реальное копирование

Хранение массивов

Массивы в PHP - это упорядоченные хеш-таблицы:

typedef struct _hashtable {
    uint32_t nTableSize;        // Размер хеш-таблицы
    uint32_t nNumOfElements;    // Количество элементов
    Bucket* arData;             // Массив бакетов
    // ... другие поля
} HashTable;

Пример в памяти:

$array = ['a' => 1, 'b' => 2];
// Хранится как хеш-таблица с двойным индексированием

Хранение объектов

С PHP 5 объекты хранятся по ссылке:

class User {
    public $name;
}

$user1 = new User();  // Создается zval типа object
$user2 = $user1;      // Копируется только указатель на объект
$user2->name = "John"; // Изменяется общий объект

Сборка мусора

PHP использует подсчет ссылок как основной механизм и циклический сборщик мусора как вспомогательный:

  1. Когда refcount достигает 0, память освобождается немедленно
  2. Для циклических ссылок запускается циклический сборщик (с PHP 5.3)

Оптимизации в PHP 8

В PHP 8 появились дополнительные оптимизации:

  • Immutable strings для строк в коде
  • JIT-компиляция влияет на доступ к переменным
  • Улучшенное хранение типизированных свойств

Практический пример работы с памятью

// Создание переменных
$x = 10;                // zval с типом IS_LONG
$y = 3.14;              // zval с типом IS_DOUBLE  
$z = "test";            // zval с типом IS_STRING
$arr = [1, 2, 3];       // zval с типом IS_ARRAY
$obj = new stdClass();  // zval с типом IS_OBJECT

// Переприсваивание
$copy = $z;             // Copy-On-Write: копируется только zval
$copy[0] = 'T';         // Реальное копирование строки

// Ссылки
$ref = &$x;            // Создается reference wrapper
$ref = 20;             // Меняется исходная переменная $x

Понимание работы zval критически важно для:

  • Оптимизации производительности приложений
  • Правильной работы со ссылками и копированием
  • Эффективного управления памятью
  • Отладки сложных сценариев с переменными

Архитектура zval эволюционировала от простой структуры с явным подсчетом ссылок до сложной системы с автоматической оптимизацией, что сделало PHP значительно быстрее при сохранении гибкости динамической типизации.