# OPcache, обяснен: кешът за байткод на PHP

> OPcache, обяснен: как работи кешът за байткод на PHP, кои настройки са важни, защо трябва да се изчиства след актуализации и как да го защитите.

Източник: https://phpsos.de/bg/php/opcache/  
Актуалност: 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

**Накратко:** OPcache е вграденият кеш за байткод на PHP. Според ръководството той съхранява предварително компилиран байткод в споделената памет, така че PHP не трябва да зарежда и превежда скриптовете при всяка заявка. Част е от доставката от PHP 5.5.0. OPcache прави PHP по-бърз, но не замества актуализацията: след PHP корекция всички PHP процеси трябва да се рестартират, а не само да се изчисти кешът.

## Какво точно прави OPcache?

При всяка заявка PHP трябва да прочете скрипта, да го разчлени и да го преведе в опкодове, т.е. в командите за виртуалната машина на [Zend Engine](https://phpsos.de/bg/php/zend-engine/). При CMS със стотици файлове това е много работа, която непрекъснато се повтаря.

OPcache съхранява резултата от това превеждане в споделената памет (shared memory). Всички работни процеси на една услуга PHP-FPM или всички процеси на Apache с mod_php я ползват. Ако даден файл не се промени, неговият байткод се използва директно повторно.

OPcache се зарежда като Zend разширение, а не като обикновено разширение:

```ini
; Linux (пътят зависи от пакета)
zend_extension=opcache.so
; Windows
; zend_extension=php_opcache.dll
```

Според ръководството OPcache трябва да се зарежда преди Xdebug, когато и двете са активни.

Важно е на кого принадлежи споделената памет. При PHP-FPM главният процес я създава и всички работни процеси на всички пулове на тази услуга я ползват. При mod_php тя принадлежи на главния процес на Apache. Рестартирането на услугата затова изчиства кеша напълно, а един отделен нов работен процес не го прави. За командния ред няма споделена памет между отделните извиквания, защото всяко извикване е самостоятелен процес; там OPcache е изключен по подразбиране.

За вземащите решения е достатъчно едно правило на палеца: OPcache почти винаги е смислен на продукционни сървъри, но изисква ясна процедура за внедряване и актуализации.

## Кои настройки на OPcache са важни?

Следващите стойности са от страницата за конфигурация в ръководството на PHP. Колоната „Променяемо“ показва къде може да се задава една настройка: `INI_SYSTEM` само в php.ini или в конфигурацията на сървъра, `INI_ALL` навсякъде.

| Директива | По подразбиране | Променяемо | Значение |
|---|---|---|---|
| `opcache.enable` | 1 | INI_ALL | кеш включен или изключен, по време на изпълнение може само да се изключи |
| `opcache.enable_cli` | 0 | INI_SYSTEM | кеш за командния ред |
| `opcache.memory_consumption` | 128 | INI_SYSTEM | размер на споделената памет в MB |
| `opcache.interned_strings_buffer` | 8 | INI_SYSTEM | памет за споделени низове в MB |
| `opcache.max_accelerated_files` | 10000 | INI_SYSTEM | максимален брой кеширани скриптове |
| `opcache.validate_timestamps` | 1 | INI_ALL | проверява дали файловете са променяни |
| `opcache.revalidate_freq` | 2 | INI_ALL | интервал на проверка в секунди, 0 = при всяка заявка |
| `opcache.restrict_api` | празно | INI_SYSTEM | позволява функциите на API само от определен път |
| `opcache.validate_permission` | 0 | INI_SYSTEM | проверява правата на файловете спрямо текущия потребител |
| `opcache.validate_root` | 0 | INI_SYSTEM | предотвратява колизии на имена при chroot |
| `opcache.file_cache` | празно | INI_SYSTEM | второ ниво на кеша на диска |

Типична продукционна конфигурация може да изглежда така. Проверете стойностите предварително с Вашето приложение:

```ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.restrict_api=/var/www/admin-tools
```

Който зададе `opcache.validate_timestamps=0`, печели малко производителност. Тогава обаче OPcache изобщо не разпознава променени файлове и всяко внедряване изисква нулиране на кеша или рестартиране.

## Наблюдение на кеша и целенасочено изчистване

OPcache носи собствени функции, сред които `opcache_get_status()`, `opcache_get_configuration()`, `opcache_invalidate()` и `opcache_reset()`. Кратък, само четящ поглед към запълването:

```php
<?php
$status = opcache_get_status(false);
if ($status === false) {
    exit("OPcache ist nicht aktiv.\n");
}
printf("Gecachte Skripte: %d\n", $status['opcache_statistics']['num_cached_scripts']);
printf("Freier Speicher: %.1f MB\n", $status['memory_usage']['free_memory'] / 1048576);
```

На сървъри с няколко уебсайта не бива всяко приложение да може да изчиства или чете кеша на всички останали. За това служи `opcache.restrict_api`: само скриптове под зададения път могат да извикват функциите на API.

## JIT: компилаторът към машинен код в OPcache

От PHP 8.0 OPcache съдържа JIT компилатор, който превежда опкодове в машинен код. Според JIT-RFC той е почти самостоятелна част от OPcache и поставя създадения код в собствена област на споделената памет. Управлява се чрез `opcache.jit` и `opcache.jit_buffer_size`. От PHP 8.4.0 `opcache.jit` по подразбиране е `disable`. Кога JIT си струва, обяснява статията [JIT и производителност в PHP 8](https://phpsos.de/bg/php/jit-und-performance/).

## OPcache и сигурност: какво важи след PHP2Shell

OPcache не е инструмент за сигурност, но има последици за сигурността. След PHP2Shell три момента са важни:

1. **Нулирането на кеша не е актуализация.** `opcache_reset()` изчиства само кеширани скриптове. Интерпретаторът с уязвимостите CVE-2026-109618 и CVE-2026-109619 остава в паметта, докато всички процеси не бъдат рестартирани. Как става това, е описано в [Рестартиране на PHP-FPM и на всички работни процеси](https://phpsos.de/bg/php2shell/php-fpm-neustart/).
2. **Вмъкнат код може да продължи да живее в кеша.** Ако даден файл е бил манипулиран и по-късно заменен, при изключена проверка на времевите отпечатъци старата версия може да продължи да се изпълнява. След почистване затова е необходимо рестартиране.
3. **Споделената памет изисква разделяне.** На сървъри с няколко клиента помагат отделни PHP-FPM пулове за всеки уебсайт, както и `opcache.validate_permission` и `opcache.restrict_api`. Директорията за `opcache.file_cache` трябва да е достъпна за запис само за потребителя на PHP.

> **Съвет:**
> След всяка актуализация проверявайте дали времето на стартиране на PHP процесите е след актуализацията. Пълен OPcache с висок процент попадения не е доказателство, че работи новият интерпретатор.

## Как помага PHP SOS конкретно?

- **Проверка на конфигурацията:** Четем активната конфигурация на OPcache за всеки режим на работа и я съгласуваме с Вашето приложение.
- **Защита на внедряванията:** Въвеждаме твърда процедура за нулиране на кеша и рестартиране, за да не продължи да работи стара версия на кода.
- **Разделяне на клиентите:** В рамките на [заздравяването на сървъра](https://phpsos.de/bg/leistungen/server-haertung/) задаваме отделни пулове, `restrict_api` и подходящи права.
- **Контрол след актуализации:** Доказваме чрез времената на стартиране на процесите, че актуализираният интерпретатор действително е активен.


## Често задавани въпроси

**OPcache активен ли е по подразбиране?**  
OPcache се доставя с PHP от версия 5.5.0 и според ръководството работи с opcache.enable=1 по подразбиране, щом разширението е заредено. Дали е заредено, зависи от Вашия пакет или хостинг доставчик. В командния ред OPcache е изключен по подразбиране (opcache.enable_cli=0).

**Защо след внедряване все още виждам стария код?**  
Вероятно OPcache проверява за промени във файловете само през определени интервали или изобщо не проверява. С opcache.revalidate_freq по подразбиране чака две секунди, с opcache.validate_timestamps=0 никога. Тогава помага само нулиране на кеша или рестартиране на PHP-FPM, респективно Apache.

**Достатъчно ли е opcache_reset() след актуализация на PHP?**  
Не. opcache_reset() изчиства само кеша с преведени скриптове. Актуализацията на PHP заменя самия интерпретатор, а той е зареден във всеки работещ процес. За това всички PHP процеси трябва да бъдат рестартирани.

**JIT включен ли е в PHP 8.4?**  
Според ръководството opcache.jit е зададен по подразбиране на disable от PHP 8.4.0, докато opcache.jit_buffer_size е 64M. Преди беше обратното: jit на tracing, буфер 0. И в двата случая JIT не е активен без съзнателна конфигурация.

## Източници

- [Ръководство на PHP: OPcache](https://www.php.net/manual/en/book.opcache.php)
- [Ръководство на PHP: Конфигурация на OPcache](https://www.php.net/manual/en/opcache.configuration.php)
- [Ръководство на PHP: Инсталиране на OPcache](https://www.php.net/manual/en/opcache.installation.php)
- [PHP RFC: JIT](https://wiki.php.net/rfc/jit)
