Kurz gesagt: OPcache ist der eingebaute Bytecode-Cache von PHP. Laut Handbuch speichert er vorkompilierten Bytecode im gemeinsamen Speicher, sodass PHP Skripte nicht bei jeder Anfrage neu laden und übersetzen muss. Er gehört seit PHP 5.5.0 zum Lieferumfang. OPcache macht PHP schneller, ersetzt aber kein Update: Nach einem PHP-Patch müssen alle PHP-Prozesse neu starten, nicht nur der Cache geleert werden.
Was macht OPcache genau?
Bei jeder Anfrage muss PHP ein Skript lesen, zerlegen und in Opcodes übersetzen, also in die Befehle für die virtuelle Maschine der Zend Engine. Bei einem CMS mit Hunderten Dateien ist das viel Arbeit, die sich ständig wiederholt.
OPcache speichert das Ergebnis dieser Übersetzung im gemeinsamen Speicher (Shared Memory). Alle Worker eines PHP-FPM-Dienstes oder alle Apache-Prozesse mit mod_php greifen darauf zu. Ändert sich eine Datei nicht, wird ihr Bytecode direkt wiederverwendet.
Geladen wird OPcache als Zend-Erweiterung, nicht als normale Erweiterung:
; Linux (Pfad je nach Paket)
zend_extension=opcache.so
; Windows
; zend_extension=php_opcache.dll
Laut Handbuch soll OPcache vor Xdebug geladen werden, wenn beide aktiv sind.
Wichtig ist, wem der gemeinsame Speicher gehört. Bei PHP-FPM legt der Master-Prozess ihn an, und alle Worker aller Pools dieses Dienstes nutzen ihn. Bei mod_php gehört er zum Apache-Hauptprozess. Ein Neustart des Dienstes leert den Cache deshalb vollständig, ein einzelner neuer Worker dagegen nicht. Für die Kommandozeile gibt es keinen gemeinsamen Speicher über Aufrufe hinweg, weil jeder Aufruf ein eigener Prozess ist; dort ist OPcache standardmäßig aus.
Für Entscheider genügt eine Faustregel: OPcache ist auf Produktionsservern fast immer sinnvoll, verlangt aber einen klaren Ablauf für Deployments und Updates.
Welche OPcache-Einstellungen zählen?
Die folgenden Werte stammen aus der Konfigurationsseite des PHP-Handbuchs. Die Spalte „Änderbar“ zeigt, wo eine Einstellung gesetzt werden darf: INI_SYSTEM nur in php.ini oder Serverkonfiguration, INI_ALL überall.
| Direktive | Standard | Änderbar | Bedeutung |
|---|---|---|---|
opcache.enable |
1 | INI_ALL | Cache an oder aus, zur Laufzeit nur abschaltbar |
opcache.enable_cli |
0 | INI_SYSTEM | Cache für die Kommandozeile |
opcache.memory_consumption |
128 | INI_SYSTEM | Größe des gemeinsamen Speichers in MB |
opcache.interned_strings_buffer |
8 | INI_SYSTEM | Speicher für gemeinsame Zeichenketten in MB |
opcache.max_accelerated_files |
10000 | INI_SYSTEM | maximale Anzahl gecachter Skripte |
opcache.validate_timestamps |
1 | INI_ALL | prüft, ob Dateien geändert wurden |
opcache.revalidate_freq |
2 | INI_ALL | Prüfabstand in Sekunden, 0 = bei jeder Anfrage |
opcache.restrict_api |
leer | INI_SYSTEM | erlaubt API-Funktionen nur aus einem Pfad |
opcache.validate_permission |
0 | INI_SYSTEM | prüft Dateirechte gegen den aktuellen Benutzer |
opcache.validate_root |
0 | INI_SYSTEM | verhindert Namenskollisionen bei chroot |
opcache.file_cache |
leer | INI_SYSTEM | zweite Cache-Ebene auf der Festplatte |
Eine typische Produktionskonfiguration könnte so aussehen. Prüfen Sie die Werte vorher mit Ihrer Anwendung:
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
Wer opcache.validate_timestamps=0 setzt, gewinnt etwas Leistung. Dann erkennt OPcache geänderte Dateien aber gar nicht mehr, und jedes Deployment braucht einen Reset des Caches oder einen Neustart.
Den Cache beobachten und gezielt leeren
OPcache bringt eigene Funktionen mit, darunter opcache_get_status(), opcache_get_configuration(), opcache_invalidate() und opcache_reset(). Ein kurzer, lesender Blick auf den Füllstand:
<?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);
Auf Servern mit mehreren Websites sollte nicht jede Anwendung den Cache aller anderen leeren oder auslesen können. Dafür ist opcache.restrict_api gedacht: Nur Skripte unterhalb des angegebenen Pfads dürfen die API-Funktionen aufrufen.
JIT: der Maschinencode-Compiler im OPcache
Seit PHP 8.0 enthält OPcache einen JIT-Compiler, der Opcodes in Maschinencode übersetzt. Laut JIT-RFC ist er ein nahezu eigenständiger Teil von OPcache und legt den erzeugten Code in einem eigenen Bereich des gemeinsamen Speichers ab. Gesteuert wird er über opcache.jit und opcache.jit_buffer_size. Seit PHP 8.4.0 steht opcache.jit standardmäßig auf disable. Wann sich der JIT lohnt, erklärt der Beitrag JIT und Performance in PHP 8.
OPcache und Sicherheit: was nach PHP2Shell gilt
OPcache ist kein Sicherheitswerkzeug, hat aber Folgen für die Sicherheit. Drei Punkte sind nach PHP2Shell wichtig:
- Ein Cache-Reset ist kein Update.
opcache_reset()leert nur gecachte Skripte. Der Interpreter mit den Lücken CVE-2026-109618 und CVE-2026-109619 bleibt im Speicher, bis alle Prozesse neu gestartet sind. Wie das geht, steht unter PHP-FPM und alle Worker neu starten. - Eingeschleuster Code kann im Cache weiterleben. Wurde eine Datei manipuliert und später ersetzt, kann bei ausgeschalteter Zeitstempelprüfung die alte Fassung weiter ausgeführt werden. Nach einer Bereinigung gehört deshalb ein Neustart dazu.
- Gemeinsamer Speicher braucht Trennung. Auf Servern mit mehreren Kunden helfen eigene PHP-FPM-Pools je Website sowie
opcache.validate_permissionundopcache.restrict_api. Ein Verzeichnis füropcache.file_cachedarf nur für den PHP-Benutzer beschreibbar sein.
Prüfen Sie nach jedem Update, ob die Startzeit der PHP-Prozesse nach dem Update liegt. Ein voller OPcache mit hoher Trefferquote ist kein Beleg dafür, dass der neue Interpreter läuft.
Wie hilft PHP SOS konkret?
- Konfiguration prüfen: Wir lesen die aktive OPcache-Konfiguration je Betriebsart aus und gleichen sie mit Ihrer Anwendung ab.
- Deployments absichern: Wir richten einen festen Ablauf für Cache-Reset und Neustart ein, damit keine alte Codefassung weiterläuft.
- Mandanten trennen: Im Rahmen der Server-Härtung setzen wir getrennte Pools,
restrict_apiund passende Rechte. - Nach Updates kontrollieren: Wir belegen über Prozess-Startzeiten, dass der aktualisierte Interpreter wirklich aktiv ist.
Häufige Fragen
Ist OPcache standardmäßig aktiv?
OPcache wird seit PHP 5.5.0 mit PHP ausgeliefert und laut Handbuch mit opcache.enable=1 als Standard betrieben, sobald die Erweiterung geladen ist. Ob sie geladen ist, hängt von Ihrem Paket oder Hoster ab. Auf der Kommandozeile ist OPcache dagegen standardmäßig aus (opcache.enable_cli=0).
Warum sehe ich nach einem Deployment noch den alten Code?
Wahrscheinlich prüft OPcache Dateiänderungen nur in Abständen oder gar nicht. Mit opcache.revalidate_freq wartet er standardmäßig zwei Sekunden, mit opcache.validate_timestamps=0 nie. Dann hilft nur ein Reset des Caches oder ein Neustart von PHP-FPM bzw. Apache.
Reicht opcache_reset() nach einem PHP-Update?
Nein. opcache_reset() leert nur den Cache mit übersetzten Skripten. Ein PHP-Update ersetzt den Interpreter selbst, und der ist in jedem laufenden Prozess geladen. Dafür müssen alle PHP-Prozesse neu gestartet werden.
Ist der JIT in PHP 8.4 eingeschaltet?
Laut Handbuch ist opcache.jit seit PHP 8.4.0 standardmäßig auf disable gesetzt, während opcache.jit_buffer_size 64M beträgt. Vorher war es umgekehrt: jit auf tracing, Puffer auf 0. In beiden Fällen ist der JIT ohne bewusste Konfiguration nicht aktiv.