# Zend Engine: сърцето на PHP

> Zend Engine, обяснена: компилатор, опкодове, виртуална машина, zval и управление на паметта в ядрото на PHP, нейните версии и значение за корекциите.

Източник: https://phpsos.de/bg/php/zend-engine/  
Актуалност: 25.10.2026  
Доставчик: PHP SOS, Спешна помощ за PHP и сигурност на сървъри. Незабавна помощ по WhatsApp: https://wa.me/491736494914?text=%D0%97%D0%B4%D1%80%D0%B0%D0%B2%D0%B5%D0%B9%D1%82%D0%B5%2C%20PHP%20SOS%2C%20%D0%B8%D0%BC%D0%B0%D0%BC%D0%B5%20%D0%BD%D1%83%D0%B6%D0%B4%D0%B0%20%D0%BE%D1%82%20%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%20%D1%81%20%D0%BD%D0%B0%D1%88%D0%B8%D1%8F%20PHP%20%D1%81%D1%8A%D1%80%D0%B2%D1%8A%D1%80.%20%D0%A4%D0%B8%D1%80%D0%BC%D0%B0%3A%20%E2%80%A6%20%D0%A3%D0%B5%D0%B1%D1%81%D0%B0%D0%B9%D1%82%3A%20%E2%80%A6

**Накратко:** Zend Engine е ядрото на PHP. Тя превежда PHP кода в опкодове, изпълнява ги във виртуална машина и при това управлява променливите и паметта. От PHP 4 насам тя е в основата на всяка инсталация на PHP. Тъй като уязвимостите на PHP2Shell се намират в това ядро, не помагат нито добавки, нито актуализации на CMS, а само актуализиран PHP с рестартиране.

## Какво е Zend Engine?

Zend Engine е частта от PHP, която върши същинската работа. Всичко останало, например връзката с уеб сървъра или разширенията за бази данни, се надгражда върху нея. Може да се сравни с двигателя на автомобила: каросерията и оборудването се различават, но двигателят задвижва всичко.

Според ръководството на PHP името е образувано от малките имена на разработчиците Зееб Сураски и Анди Гутманс. Машината е представена в средата на 1999 г. и от PHP 4.0, издаден през май 2000 г., е ядрото на PHP. Оттогава тя е преработвана основно няколко пъти.

| Версия на PHP | Машина | Най-важна промяна според ръководството и RFC |
|---|---|---|
| PHP 4.0 (2000 г.) | Zend Engine | първо общо ядро, по-добра производителност |
| PHP 5.0 (2004 г.) | Zend Engine 2.0 | нов обектен модел |
| PHP 7.0 (2015 г.) | Zend Engine 3.0 | PHPNG: по-компактни структури от данни, AST |
| PHP 8.0 (2020 г.) | Развитие | JIT компилатор като част от OPcache |

## Компонентите: компилатор, виртуална машина, памет

Машината работи на ясно разделени етапи. От PHP 7 според RFC за абстрактното синтактично дърво до байткода има три фази:

1. **Лексер:** разчленява изходния код на токени, например ключови думи, имена на променливи и низове.
2. **Парсер:** изгражда от токените абстрактно синтактично дърво (AST), което отразява структурата на програмата.
3. **Компилатор:** създава от AST op-масиви, т.е. списъци от опкодове, по един за всеки файл и функция.
4. **Изпълнител (Zend VM):** обработва опкодовете. Според JIT-RFC към всеки опкод принадлежи функция-обработчик, която го изпълнява.
5. **Управление на паметта:** резервира и освобождава памет за всяка заявка и при това следи границата от `memory_limit`.

Токените на един скрипт могат да се покажат с разширението Tokenizer. Това е безобидно и поучително:

```php
<?php
$code = '<?php $summe = 2 + 3; echo $summe;';
foreach (token_get_all($code) as $token) {
    if (is_array($token)) {
        echo token_name($token[0]), ': ', trim($token[1]), "\n";
    } else {
        echo 'Zeichen: ', $token, "\n";
    }
}
```

Изходът показва записи като `T_VARIABLE: $summe` или `T_LNUMBER: 2`. Точно с тези градивни елементи парсерът продължава да работи.

## Как Zend Engine управлява променливите?

Според ръководството всяка PHP променлива се намира в контейнер, наречен zval. Той съдържа тип и стойност, както и служебни данни, сред които брояч на референциите (refcount). Броячът показва колко имена на променливи сочат към един и същ контейнер.

```php
<?php
$a = str_repeat('x', 10);
$b = $a;        // без копиране, и двете сочат към една и съща стойност
$b .= 'y';      // едва сега се копира (copy on write)
unset($a);      // броячът намалява, паметта се освобождава, когато стигне 0
```

Когато броячът достигне нула, машината освобождава паметта. За кръгови препратки между обекти има допълнително събирач на боклук (garbage collector). Повече по темата в статията [Управление на паметта в PHP](https://phpsos.de/bg/php/speicherverwaltung/).

Преработката PHPNG за PHP 7 се насочва именно натам. Според RFC на Дмитрий Стогов и Зееб Сураски целта била по-компактни структури от данни и по-находчиво представяне на стойностите. RFC посочва ръст на производителността от 20 до 110 процента при реални приложения.

## OPcache и JIT: разширения на машината

Без кеш машината превежда всеки скрипт наново при всяка заявка. [OPcache](https://phpsos.de/bg/php/opcache/) държи готовите опкодове в споделената памет. От PHP 8.0 има допълнително JIT компилатор. Според RFC той се основава на DynASM, инструмент от проекта LuaJIT, и създава машинен код директно от байткода. Виртуалната машина при това остава непроменена; JIT заменя само входните точки на обработчиците.

За операторите това означава: OPcache и JIT ускоряват машината, но не променят поведението ѝ при грешки. Уязвимост в ядрото остава и при активен кеш.

## Защо уязвимостите в машината тежат особено

Двете уязвимости на PHP2Shell се намират в ядрото на PHP. При CVE-2026-109618 състояние на изчерпана памет (out-of-memory) може да прекъсне машината, докато данните от заявката са инициализирани само частично; при почистването невалидни данни след това се третират като валидни. При CVE-2026-109619 вътрешно състояние остава след освобождаването на паметта и може да бъде използвано от по-късна заявка в същия работен процес.

Поправените версии 8.5.12, 8.4.27, 8.3.36 и 8.2.35 според ръководството на PHP променят и поведението на границата на паметта: `memory_limit` там е мека граница, а нова настройка `memory_hard_limit_percent` задава твърда горна граница. Ръководството посочва, че версия, която не познава тази настройка, е засегната от уязвимостите. При дистрибуции с backport корекции допълнително значение има дневникът на промените на пакета.

> **Важно:**
> Машината е заредена във всеки PHP процес. Затова след актуализацията всички PHP-FPM работни процеси, процесите на Apache с mod_php и останалите PHP услуги трябва да бъдат рестартирани.

Какво се случва вътрешно при недостиг на памет, описва статията [memory_limit и Out-of-Memory](https://phpsos.de/bg/php/out-of-memory/). Класификацията на самата уязвимост е на страницата [CVE-2026-109618](https://phpsos.de/bg/php2shell/cve-2026-109618/).

## Как помага PHP SOS конкретно?

- **Проверка на версията и състоянието на пакета:** Установяваме кое състояние на машината действително работи, включително backport корекциите на Вашата дистрибуция.
- **Актуализиране и рестартиране:** Чрез [услугата за PHP корекции](https://phpsos.de/bg/leistungen/php-patch-service/) внасяме актуализацията и контролираме да не остане процес със стар код.
- **Смислено задаване на ограниченията на паметта:** Съгласуваме `memory_limit`, новата твърда граница и ограниченията на cgroup с Вашето приложение.
- **Разследване на необичайни случаи:** Сривове на работни процеси или процеси със статус на изход 137 класифицираме и проверяваме дали зад тях може да стои атака.


## Често задавани въпроси

**Откъде идва името Zend Engine?**  
Името е съставено от малките имена на нейните разработчици: Зееб Сураски и Анди Гутманс. Според ръководството на PHP машината е представена в средата на 1999 г. и от PHP 4.0 през май 2000 г. е ядрото на PHP.

**Zend Engine самостоятелен продукт ли е, който трябва да инсталирам?**  
Не. Zend Engine е неразделна част от всяка инсталация на PHP. Който актуализира PHP, автоматично актуализира и машината. С търговските продукти на фирмата Zend това няма нищо общо.

**Какво е опкод?**  
Опкодът е отделна команда за виртуалната машина на PHP, например събиране, извикване на функция или присвояване. Компилаторът превежда всеки скрипт в последователност от такива команди, които машината след това обработва.

**Какво общо има Zend Engine с memory_limit?**  
Машината управлява паметта на всяка заявка и следи границата от memory_limit. От изданията за сигурност от 21.10.2026 г. тази граница според ръководството е мека граница, допълнена от твърда граница чрез memory_hard_limit_percent.

## Източници

- [Ръководство на PHP: История на PHP](https://www.php.net/manual/en/history.php.php)
- [PHP RFC: PHPNG](https://wiki.php.net/rfc/phpng)
- [PHP RFC: JIT](https://wiki.php.net/rfc/jit)
- [Ръководство на PHP: Броене на референции](https://www.php.net/manual/en/features.gc.refcounting-basics.php)
- [Ръководство на PHP: Основни настройки (memory_limit)](https://www.php.net/manual/en/ini.core.php)
