# Zend Engine: serce PHP

> Zend Engine wyjaśniony: kompilator, opcody, maszyna wirtualna, zval i zarządzanie pamięcią w rdzeniu PHP, jego wersje i znaczenie dla poprawek.

Źródło: https://phpsos.de/pl/php/zend-engine/  
Stan: 25.10.2026  
Dostawca: PHP SOS, Pomoc awaryjna PHP i bezpieczeństwo serwerów. Natychmiastowa pomoc przez WhatsApp: https://wa.me/491736494914?text=Dzie%C5%84%20dobry%2C%20PHP%20SOS%2C%20potrzebujemy%20pomocy%20z%20naszym%20serwerem%20PHP.%20Firma%3A%20%E2%80%A6%20Strona%20internetowa%3A%20%E2%80%A6

**Krótko:** Zend Engine to rdzeń PHP. Tłumaczy kod PHP na opcody, wykonuje je w maszynie wirtualnej i zarządza przy tym zmiennymi oraz pamięcią. Od PHP 4 znajduje się w każdej instalacji PHP. Ponieważ luki PHP2Shell tkwią w tym rdzeniu, nie pomagają wtyczki ani aktualizacje CMS, lecz tylko zaktualizowane PHP z restartem.

## Czym jest Zend Engine?

Zend Engine to ta część PHP, która wykonuje właściwą pracę. Wszystko inne, na przykład połączenie z serwerem WWW czy rozszerzenia do baz danych, opiera się na niej. Można ją porównać do silnika samochodu: nadwozie i wyposażenie się różnią, a silnik napędza wszystko.

Według podręcznika PHP nazwa powstała z imion twórców, Zeeva Suraskiego i Andiego Gutmansa. Silnik przedstawiono w połowie 1999 roku, a od PHP 4.0, wydanego w maju 2000 roku, był rdzeniem PHP. Od tego czasu był kilkakrotnie gruntownie przepracowywany.

| Wersja PHP | Silnik | Najważniejsza zmiana według podręcznika i RFC |
|---|---|---|
| PHP 4.0 (2000) | Zend Engine | pierwszy wspólny rdzeń, lepsza wydajność |
| PHP 5.0 (2004) | Zend Engine 2.0 | nowy model obiektowy |
| PHP 7.0 (2015) | Zend Engine 3.0 | PHPNG: bardziej zwarte struktury danych, AST |
| PHP 8.0 (2020) | dalszy rozwój | kompilator JIT jako część OPcache |

## Elementy: kompilator, maszyna wirtualna, pamięć

Silnik pracuje w wyraźnie rozdzielonych etapach. Od PHP 7 według RFC o abstrakcyjnym drzewie składni są to trzy fazy do bajtkodu:

1. **Lexer:** rozbija kod źródłowy na tokeny, na przykład słowa kluczowe, nazwy zmiennych i ciągi znaków.
2. **Parser:** buduje z tokenów abstrakcyjne drzewo składni (AST), które odwzorowuje strukturę programu.
3. **Kompilator:** tworzy z AST tablice op, czyli listy opcodów, po jednej dla każdego pliku i funkcji.
4. **Executor (Zend VM):** przetwarza opcody. Według RFC dotyczącego JIT do każdego opcode należy funkcja obsługi, która go wykonuje.
5. **Zarządzanie pamięcią:** rezerwuje i zwalnia pamięć dla każdego żądania, pilnując przy tym limitu z `memory_limit`.

Tokeny skryptu można uwidocznić za pomocą rozszerzenia Tokenizer. To nieszkodliwe i pouczające:

```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";
    }
}
```

Wyjście pokazuje wpisy takie jak `T_VARIABLE: $summe` czy `T_LNUMBER: 2`. Z takimi właśnie elementami parser pracuje dalej.

## Jak Zend Engine zarządza zmiennymi?

Według podręcznika każda zmienna PHP leży w kontenerze o nazwie zval. Zawiera typ i wartość oraz informacje zarządcze, w tym licznik referencji (refcount). Licznik wskazuje, ile nazw zmiennych wskazuje na ten sam kontener.

```php
<?php
$a = str_repeat('x', 10);
$b = $a;        // brak kopiowania, obie wskazują na tę samą wartość
$b .= 'y';      // dopiero teraz następuje kopiowanie (copy on write)
unset($a);      // licznik maleje, pamięć zostaje zwolniona, gdy osiągnie 0
```

Gdy licznik osiąga zero, silnik zwalnia pamięć. Dla odwołań cyklicznych między obiektami istnieje dodatkowo garbage collector. Więcej w artykule [Zarządzanie pamięcią w PHP](https://phpsos.de/pl/php/speicherverwaltung/).

Przepracowanie PHPNG dla PHP 7 dotyczyło właśnie tego miejsca. Według RFC autorstwa Dmitrego Stogova i Zeeva Suraskiego chodziło o bardziej zwarte struktury danych i zręczniejszą reprezentację wartości. RFC podawał wzrost wydajności od 20 do 110 procent w rzeczywistych aplikacjach.

## OPcache i JIT: rozszerzenia silnika

Bez pamięci podręcznej silnik tłumaczy każdy skrypt od nowa przy każdym żądaniu. [OPcache](https://phpsos.de/pl/php/opcache/) trzyma gotowe opcody we wspólnej pamięci. Od PHP 8.0 istnieje dodatkowo kompilator JIT. Według RFC opiera się na DynASM, narzędziu z projektu LuaJIT, i tworzy kod maszynowy bezpośrednio z bajtkodu. Maszyna wirtualna pozostaje przy tym niezmieniona; JIT zastępuje tylko punkty wejścia funkcji obsługi.

Dla operatorów oznacza to: OPcache i JIT przyspieszają silnik, ale nie zmieniają jego zachowania w razie błędów. Luka w rdzeniu pozostaje także przy aktywnej pamięci podręcznej.

## Dlaczego luki w silniku są szczególnie poważne

Obie luki PHP2Shell tkwią w rdzeniu PHP. W przypadku CVE-2026-109618 stan braku pamięci (out of memory) może przerwać silnik, gdy dane żądania są dopiero częściowo zainicjowane; przy sprzątaniu nieprawidłowe dane są wtedy traktowane jako prawidłowe. W przypadku CVE-2026-109619 wewnętrzny stan pozostaje po zwolnieniu pamięci i może zostać użyty przez późniejsze żądanie w tym samym workerze.

Poprawione wersje 8.5.12, 8.4.27, 8.3.36 i 8.2.35 zmieniają według podręcznika PHP także zachowanie limitu pamięci: `memory_limit` jest tam limitem miękkim, a nowe ustawienie `memory_hard_limit_percent` określa twardą górną granicę. Podręcznik zwraca uwagę, że wersja, która tego ustawienia nie zna, jest dotknięta lukami. W dystrybucjach z backportami dodatkowo liczy się changelog pakietu.

> **Ważne:**
> Silnik jest załadowany w każdym procesie PHP. Po aktualizacji należy więc zrestartować wszystkie workery PHP-FPM, procesy Apache z mod_php i pozostałe usługi PHP.

Co dzieje się wewnątrz przy braku pamięci, opisuje artykuł [memory_limit i out of memory](https://phpsos.de/pl/php/out-of-memory/). Ocenę samej luki podajemy na stronie [CVE-2026-109618](https://phpsos.de/pl/php2shell/cve-2026-109618/).

## Jak konkretnie pomaga PHP SOS?

- **Sprawdzenie wersji i stanu pakietów:** Ustalamy, jaki stan silnika faktycznie działa, łącznie z backportami Państwa dystrybucji.
- **Aktualizacja i restart:** W ramach [usługi PHP Patch Service](https://phpsos.de/pl/leistungen/php-patch-service/) instalujemy aktualizację i kontrolujemy, że nie został żaden proces ze starym kodem.
- **Sensowne ustawienie limitów pamięci:** Dopasowujemy `memory_limit`, nowy limit twardy i limity cgroup do Państwa aplikacji.
- **Badanie nieprawidłowości:** Awarie workerów lub procesy ze statusem wyjścia 137 oceniamy i sprawdzamy, czy może za nimi stać atak.


## Częste pytania

**Skąd Zend Engine ma swoją nazwę?**  
Nazwa składa się z imion jej twórców: Zeeva Suraskiego i Andiego Gutmansa. Według podręcznika PHP silnik przedstawiono w połowie 1999 roku, a od PHP 4.0 w maju 2000 roku był rdzeniem PHP.

**Czy Zend Engine to odrębny produkt, który muszę zainstalować?**  
Nie. Zend Engine jest stałym składnikiem każdej instalacji PHP. Kto aktualizuje PHP, automatycznie aktualizuje także silnik. Z komercyjnymi produktami firmy Zend nie ma to nic wspólnego.

**Czym jest opcode?**  
Opcode to pojedyncze polecenie dla maszyny wirtualnej PHP, na przykład dodawanie, wywołanie funkcji lub przypisanie. Kompilator tłumaczy każdy skrypt na ciąg takich poleceń, które silnik następnie wykonuje.

**Co Zend Engine ma wspólnego z memory_limit?**  
Silnik zarządza pamięcią każdego żądania i pilnuje przy tym limitu z memory_limit. Od wydań bezpieczeństwa z 21.10.2026 limit ten jest według podręcznika limitem miękkim, uzupełnionym limitem twardym przez memory_hard_limit_percent.

## Źródła

- [Podręcznik PHP: historia 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)
- [Podręcznik PHP: zliczanie referencji](https://www.php.net/manual/en/features.gc.refcounting-basics.php)
- [Podręcznik PHP: ustawienia rdzenia (memory_limit)](https://www.php.net/manual/en/ini.core.php)
