Накратко: OPcache е вграденият кеш за байткод на PHP. Според ръководството той съхранява предварително компилиран байткод в споделената памет, така че PHP не трябва да зарежда и превежда скриптовете при всяка заявка. Част е от доставката от PHP 5.5.0. OPcache прави PHP по-бърз, но не замества актуализацията: след PHP корекция всички PHP процеси трябва да се рестартират, а не само да се изчисти кешът.
Какво точно прави OPcache?
При всяка заявка PHP трябва да прочете скрипта, да го разчлени и да го преведе в опкодове, т.е. в командите за виртуалната машина на Zend Engine. При CMS със стотици файлове това е много работа, която непрекъснато се повтаря.
OPcache съхранява резултата от това превеждане в споделената памет (shared memory). Всички работни процеси на една услуга PHP-FPM или всички процеси на Apache с mod_php я ползват. Ако даден файл не се промени, неговият байткод се използва директно повторно.
OPcache се зарежда като Zend разширение, а не като обикновено разширение:
; 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 | второ ниво на кеша на диска |
Типична продукционна конфигурация може да изглежда така. Проверете стойностите предварително с Вашето приложение:
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
$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.
OPcache и сигурност: какво важи след PHP2Shell
OPcache не е инструмент за сигурност, но има последици за сигурността. След PHP2Shell три момента са важни:
- Нулирането на кеша не е актуализация.
opcache_reset()изчиства само кеширани скриптове. Интерпретаторът с уязвимостите CVE-2026-109618 и CVE-2026-109619 остава в паметта, докато всички процеси не бъдат рестартирани. Как става това, е описано в Рестартиране на PHP-FPM и на всички работни процеси. - Вмъкнат код може да продължи да живее в кеша. Ако даден файл е бил манипулиран и по-късно заменен, при изключена проверка на времевите отпечатъци старата версия може да продължи да се изпълнява. След почистване затова е необходимо рестартиране.
- Споделената памет изисква разделяне. На сървъри с няколко клиента помагат отделни PHP-FPM пулове за всеки уебсайт, както и
opcache.validate_permissionиopcache.restrict_api. Директорията заopcache.file_cacheтрябва да е достъпна за запис само за потребителя на PHP.
След всяка актуализация проверявайте дали времето на стартиране на PHP процесите е след актуализацията. Пълен OPcache с висок процент попадения не е доказателство, че работи новият интерпретатор.
Как помага PHP SOS конкретно?
- Проверка на конфигурацията: Четем активната конфигурация на OPcache за всеки режим на работа и я съгласуваме с Вашето приложение.
- Защита на внедряванията: Въвеждаме твърда процедура за нулиране на кеша и рестартиране, за да не продължи да работи стара версия на кода.
- Разделяне на клиентите: В рамките на заздравяването на сървъра задаваме отделни пулове,
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 не е активен без съзнателна конфигурация.