{"id":16681,"date":"2026-03-11T23:45:00","date_gmt":"2026-03-11T22:45:00","guid":{"rendered":"https:\/\/u-labs.de\/portal\/?p=16681"},"modified":"2026-03-19T19:36:58","modified_gmt":"2026-03-19T18:36:58","slug":"php-beschleunigen-praxis","status":"publish","type":"post","link":"https:\/\/u-labs.de\/portal\/php-beschleunigen-praxis\/","title":{"rendered":"PHP mit OPcache, Variablen-Cache &amp; JIT stark beschleunigen (Teil 2: Praxis)"},"content":{"rendered":"<p>Wie muss eine PHP-Installation aussehen, um von den zahlreichen Performance-Verbesserungen (v.a. Caching) der letzten Versionen zu profitieren? Dieser Beitrag demonstriert das an einer praktischen Umgebung, welche direkt f\u00fcr eigene Anwendungen oder dem Betreiben von Drittanbieter-Anwendungen genutzt werden kann. Darauf liegt der Fokus: Beispiele, die sich direkt ausprobieren sowie einsetzen lassen. Auf die Funktion &amp; Hintergr\u00fcnde gehe ich an dieser Stelle nur nebenbei sowie rudiment\u00e4r ein. Wer dies vertiefen m\u00f6chte, <a href=\"https:\/\/u-labs.de\/portal\/php-caches-performance-funktion\/\">findet mit dem ersten Teil einen kompletten Artikel, der die Details erl\u00e4utert<\/a>. Er ist als Grundlage empfehlenswert, um Aufbau &amp; Entwicklung besser nachvollziehen zu k\u00f6nnen.<\/p>\n<h2 class=\"wp-block-heading\">Alle aktuellen Versionen profitieren stark<\/h2>\n<p>Zum Verfassungszeitpunkt dieses Artikels ist PHP 8.2 die \u00e4lteste Version, welche noch bis Ende 2026 mit Sicherheitskorrekturen versorgt wird. Alle unterst\u00fctzten Versionen k\u00f6nnen somit von den genannten Vorteilen profitieren. Allerdings ist nur der OPcache automatisch eingeschaltet, der Rest nicht. Und selbst das nur in bestimmten Konfigurationen. Ein offizielles Standard PHP 7.4 Docker Abbild beispielsweise l\u00e4sst den OPcache weiterhin vermissen:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_15-39.avif\"><img loading=\"lazy\" decoding=\"async\" width=\"950\" height=\"85\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_15-39.avif\" alt=\"\" class=\"wp-image-16606\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_15-39.avif 950w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_15-39-300x27.avif 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_15-39-768x69.avif 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_15-39-640x57.avif 640w\" sizes=\"auto, (max-width: 950px) 100vw, 950px\" \/><\/a><\/figure>\n<\/div>\n<p>Obwohl er bereits seit Version 5.5 zum Kern von PHP geh\u00f6rt. \u00c4hnliches kann auftreten, wenn von Distributionen angepasste Pakete zum Einsatz kommen. Eine Standard-Installation von PHP besteht bei mir daher im aktivieren aller Module sowie dem Installieren von APCu. Man sollte in der eigenen Umgebung stets zu Beginn pr\u00fcfen, welche Module installiert &amp; aktiviert sind.<\/p>\n<p>Grunds\u00e4tzlich kann man sie in jeder Umgebung verwenden. Seit \u00fcber 10 Jahren laufen meine PHP-Installationen unter Docker. Es ist der flexibelste Weg. L\u00e4ngst existieren offizielle Abbilder, die das Installieren von Erweiterungen mit Hilfsfunktionen wie <code class=\"\" data-line=\"\">docker-php-ext-install <\/code>zum Kinderspiel machen. Daher zeige ich den folgenden Weg anhand der Dockerfiles meiner Projekte. Wer eine direkte Installation bevorzugt, kann die \u00c4nderungen auf manuellem Wege an die eigene Umgebung angepasst (z.B. Pfade von Konfigurationsdateien, Aufbau usw.) \u00fcbertragen.<\/p>\n<h2 class=\"wp-block-heading\">Nutzung in der Praxis: Aufbau &#8211; PHP + OPcache + JIT + APCu auf Docker<\/h2>\n<p>Als Basis verwende ich das von PHP offiziell bereitgestellte Apache-Abbild. Man kann hierbei bem\u00e4ngeln, dass mod_php f\u00fcr jede Anfrage einen PHP-Prozess startet. Ein Prozessmanager wie PHP-FPM ist effizienter, diesen setze ich bei den meisten meiner Projekte ein. Hier verzichte ich bewusst darauf, da er die Komplexit\u00e4t erh\u00f6ht. Der Fokus soll nicht auf dem Konfigurieren (und ggf. Verstehen) von PHP-FPM liegen. Sondern auf PHP mit Opcache, JIT &amp; APCu. Zumal der Vorteil des Prozessmanagers in kleineren Umgebungen gering ist, doch das w\u00e4re Stoff f\u00fcr einen eigenen Beitrag. Auch auf weitere Komponenten wie PDO mit einem Datenbanktreiber (meist MySQL\/PostgreSQL) gehe ich an dieser Stelle nicht ein.<\/p>\n<p>Wir legen uns also ein Dockerfile an, in dem zun\u00e4chst APCu installiert werden muss. Dar\u00fcber hinaus ist nur das Aktivieren per Konfigurationsdatei notwendig. Die php.ini liegt im Apache-Abbild unter <code class=\"\" data-line=\"\">\/usr\/local\/etc\/php<\/code>.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">FROM php:8.5-apache\n# PHP &gt;= 8.5 bundles OpCache, but only for caching bytecode of PHP scripts. APCu allows caching variables \nRUN pecl install APCu \\\n        &amp;&amp; docker-php-ext-enable apcu<\/code><\/pre>\n<p>Das reicht f\u00fcr eine minimale Installation bereits aus. In <code class=\"\" data-line=\"\">php-overrides.ini<\/code> \u00fcberschreiben wir Einstellungen aus der standardm\u00e4\u00dfig vorhandenen <code class=\"\" data-line=\"\">php.ini<\/code>. <\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-ini\" data-line=\"\">opcache.enable=1\n; Speicher, der dem OPcache fuer bytecode zur Verfuegung steht\nopcache.memory_consumption=64MB\n; Speicherlimit fuer JIT\nopcache.jit_buffer_size=128M\nopcache.jit=tracing\n\n; &quot;Aufwaerm&quot; Skript, welches beim Start bereits geladen + gecached wird\n;opcache.preload=\/var\/www\/preload.php\n;opcache.preload_user=www-data\n\n; Limit fuer den Objektspeicher APCu\napc.shm_size=64M\n\n; Fehlersuche: 2 = Warnungen, 3 = Info, 4 = Debug\n;opcache.log_verbosity_level=4\n\n; Produktiv: revalidate_freq hoch setzen (Standard 2s) oder Pruefung ganz abschalten \n;opcache.validate_timestamps=0\n;opcache.revalidate_freq=0<\/code><\/pre>\n<p>Damit das funktioniert, lassen wir sie in <code class=\"\" data-line=\"\">docker-compose.yml<\/code> als letztes laden. Zur Vereinfachung bei Testzwecken erfolgt das Einh\u00e4ngen der PHP-Dateien als Volumes. Produktiv sauberer w\u00e4re es, diese per <code class=\"\" data-line=\"\">COPY<\/code> ins Docker-Abbild zu kopieren. Sowie \u00fcber <code class=\"\" data-line=\"\">develop.watch<\/code> auf \u00c4nderungen zu reagieren. Auch das entf\u00e4llt hier, um es simpel zu halten.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\">services:\n  opcache-demo:\n    build: .\n    volumes:\n      - .\/www:\/var\/www\/html\n      - .\/preload.php:\/var\/www\/preload.php\n      - .\/php-overrides.ini:\/usr\/local\/etc\/php\/conf.d\/z-php-overrides.ini\n    ports:\n      - 80:80<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Aufw\u00e4rmen mit <em>Preload<\/em><\/h2>\n<p>Wir haben nun zwei robuste Zwischenspeicher. Allerdings mit einem Nachteil: Erst ab der zweiten Abfrage spielen sie ihre Karten aus. Der erste Besucher wird langsamere Ladezeiten abbekommen &#8211; insbesondere bei komplexen CMS bzw. Webanwendungen. Das kann durch <em>Aufw\u00e4rmen<\/em> gel\u00f6st werden. Dabei laden wir wichtige Teile oder die komplette Applikation direkt nach dem Start in den Cache. Dies erledigt ein PHP-Skript, welches wir \u00fcber die <code class=\"\" data-line=\"\">opcache.preload<\/code> Direktive \u00fcbergeben. Dies kann theoretisch index.php sein, praktisch rate ich davon ab. In meinen Tests hat selbst die Ausgabe der PHP-Info zum Absturz des Webservers gef\u00fchrt.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">[Mon Feb 23 17:14:58.602586 2026] [:emerg] [pid 1:tid 1] AH00020: Configuration Failed, exiting<\/code><\/pre>\n<p>Stabiler funktioniert ein eigenes PHP-Skript, welches h\u00e4ufig ben\u00f6tigte Klassen\/Dateien l\u00e4dt. Ich platziere es au\u00dferhalb des \u00f6ffentlich zug\u00e4nglichen <code class=\"\" data-line=\"\">www<\/code> Ordners, also bei Apache in <code class=\"\" data-line=\"\">\/var\/www\/preload.php<\/code>. Darin m\u00fcssen keine Objekte Erzeugt werden &#8211; es gen\u00fcgt, die PHP-Skripte per <code class=\"\" data-line=\"\">require_once<\/code> zu laden.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-php\" data-line=\"\">&lt;?php\nrequire_once __DIR__ . &#039;\/html\/demo.php&#039;;<\/code><\/pre>\n<p>Dass dies funktioniert, seht ihr mit <code class=\"\" data-line=\"\">opcache.log_verbosity_level=3<\/code> oder h\u00f6her. Er l\u00e4dt \u00fcber preload.php das Demo-Skript in den OPcache. Beim ersten Aufruf davon erscheint kein Logeintrag zum Caching mehr, weil es bereits drin liegt:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">opcache-demo-1  | Mon Feb 23 17:20:12 2026 (17): Message Cached script &#039;$PRELOAD$&#039;\nopcache-demo-1  | Mon Feb 23 17:20:12 2026 (17): Message Cached script &#039;\/var\/www\/preload.php&#039;\nopcache-demo-1  | Mon Feb 23 17:20:12 2026 (17): Message Cached script &#039;\/var\/www\/html\/demo.php&#039;\nopcache-demo-1  | 172.26.0.1 - - [23\/Feb\/2026:17:20:42 +0000] &quot;GET \/demo.php HTTP\/1.1&quot; 200 380 &quot;-&quot; &quot;Mozilla\/5.0 (X11; Linux x86_64; rv:147.0) Gecko\/20100101 Firefox\/147.0&quot;<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Den Objekt-Cache benutzen<\/h2>\n<p>Im Gegensatz zum OPcache erfordert der Objekt-Cache Anpassungen am Code der Zielanwendung: Sie muss sinnvoll Daten in den Zwischenspeicher legen. Sowie im besten Falle diese leeren, sobald die gespeicherten Daten nicht mehr aktuell sind. Ein Simples Beispiel demonstriert folgendes Skript:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-php\" data-line=\"\">&lt;?php\n$date = new DateTime();\n$dt = $date-&gt;format(&#039;d.m.Y \\u\\m H:i:s&#039;);\n\n$added = (bool)apcu_add(&#039;datetime&#039;, $dt);\n$dtCached = apcu_fetch(&#039;datetime&#039;);\n?&gt;\n&lt;h2 style=&quot;font-family:Roboto&quot;&gt;\n    Datum &amp; Uhrzeit: &lt;?=$dt?&gt;&lt;br \/&gt;\n    Zeitstempel vom Cache: &lt;?=$dtCached?&gt;&lt;br\/&gt;\n    APCu gespeichert: &lt;?=json_encode($added)?&gt;\n&lt;\/h2&gt;<\/code><\/pre>\n<p>Es gibt zuerst via <code class=\"\" data-line=\"\">$dt<\/code> den aktuellen Zeitstempel aus, welcher beim Aufruf des Skriptes neu generiert wird. Beim ersten Mal legt es ihn unter dem Schl\u00fcssel <code class=\"\" data-line=\"\">datetime<\/code> in APCu ab. Wer die Doku aufmerksam lie\u00dft, stellt fest: <code class=\"\" data-line=\"\">apcu_add<\/code> speichert nur, sofern noch nichts im Zwischenspeicher liegt. Dagegen w\u00fcrde <code class=\"\" data-line=\"\">apcu_store<\/code> s\u00e4mtliche vorhandenen Daten immer \u00fcberschreiben. Der erste Aufruf schreibt den Zeitstempel in den Cache. Die sp\u00e4teren Anfragen zeigen zwei verschiedene Zeitstempel an: Der Erste ist live generiert, weil normale PHP-Variablen w\u00e4hrend #2 dem ersten Laden entspricht.<\/p>\n<p>W\u00e4hrend das eine gute Demonstration zum Verst\u00e4ndnis der Funktion f\u00fcr den ersten Einstieg darstellt, ist es im praktischen Einsatz sinnlos. Dort w\u00fcrde man wie folgt vorgehen: Pr\u00fcfen, ob der Schl\u00fcssel bereits im Cache liegt &#8211; wenn ja, ihn von dort laden. Andernfalls m\u00fcssen die Daten geladen\/generiert\/aufbereitet werden. Zus\u00e4tzlich speichern wir sie f\u00fcr den sp\u00e4teren Abruf im Cache. Der Zeitstempel steht hier beispielhaft f\u00fcr umfangreichere Daten, etwa von einer Datenbankabfrage, einem API-Aufruf oder andere komplexere Quellen.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-php\" data-line=\"\">&lt;?php\n$key = &#039;datetime&#039;;\nif(apcu_exists($key)) {\n    $dt = apcu_fetch($key);\n}else {\n    $date = new DateTime();\n    $dt = $date-&gt;format(&#039;d.m.Y \\u\\m H:i:s&#039;);\n    apcu_add($key, $dt);\n}\n?&gt;\n&lt;h2 style=&quot;font-family:Roboto&quot;&gt;\n    Zeitstempel vom Cache: &lt;?=$dt?&gt;\n&lt;\/h2&gt;<\/code><\/pre>\n<p>Produktiv w\u00e4re es am besten, wenn die Anwendung den Zwischenspeicher automatisch leert, um immer aktuelle Daten auszuliefern. Ein Beispiel: Wir speichern die Liste der neuesten Blogbeitr\u00e4ge in APCu. Beim Hinzuf\u00fcgen neuer Eintr\u00e4ge ruft die Anwendung <code class=\"\" data-line=\"\">apcu_delete()<\/code> auf. So erscheinen keine \u00e4lteren Eintr\u00e4ge. Ist das nicht m\u00f6glich, weil die Daten von au\u00dfen ver\u00e4ndert werden, kann alternativ zumindest eine TTL (Time-to-live) angegeben werden. Daf\u00fcr akzeptiert <code class=\"\" data-line=\"\">apcu_add<\/code> als dritten Parameter die Anzahl an Sekunden. Folgendes Beispiel speichert das Datum im Schl\u00fcssel &#8222;key&#8220; f\u00fcr maximal 10 Minuten.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-php\" data-line=\"\">apcu_add(&#039;date&#039;, &#039;23.02.2026&#039;, 60*10);<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Statistiken: Wie geht es den Caches?<\/h2>\n<p>Alle Komponenten stellen PHP-Funktionen bereit, um den Status auslesen zu k\u00f6nnen. Ich habe mir dazu eine kleine Fu\u00dfzeile gebaut, welche die interessantesten Metriken darstellt. Zu Beginn von index.php (mein MVC-Router) wird die Zeit festgehalten:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-php\" data-line=\"\">define(&#039;SCRIPT_START_TIME&#039;, microtime(true));<\/code><\/pre>\n<p>So l\u00e4sst sich am Ende die Generierungszeit berechnen. Dies stelle ich zusammen mit weiteren Messwerten (etwa dem RAM-Verbrauch) sowie den Statistiken der Caches in einer kleinen unauff\u00e4lligen Box dar. Wichtig ist, dass folgender Code am Ende des Skripts aufgerufen wird! Erfolgt der Aufruf fr\u00fcher, sind Werte wie die Ausf\u00fchrungszeit oder der RAM-Verbrauch nicht korrekt. Auch die Cache-Statistik kann fehlerhaft sein, falls danach weitere Zugriffe stattfinden. Interessant ist es, nach einiger Zeit produktiver Nutzung auf die Zahlen zu Blicken. So l\u00e4sst sich erkennen, ob die reservierten Dimensionen ausreichen, oder angepasst werden k\u00f6nnen\/sollten.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-php\" data-line=\"\">&lt;?php\n$totalExecutionTime = round((microtime(true) - SCRIPT_START_TIME) * 1000, 1);\n$filesCount = count(get_included_files());\n$memory = round(memory_get_peak_usage(real_usage: false) \/ 1000, 1);\n$realMemory = round(memory_get_peak_usage(real_usage: true) \/ 1000, 1);\n$peakMemory = round(memory_get_peak_usage(real_usage: false) \/ 1000, 1);\n$realPeakMemory = round(memory_get_peak_usage(real_usage: true) \/ 1000, 1);\n\n$opcache = opcache_get_status();\n\n$apcuCache = apcu_sma_info();\n$apcuSize = round($apcuCache[&#039;seg_size&#039;] \/ 1000 \/ 1000, 1);\n$apcuAvailable = round($apcuCache[&#039;avail_mem&#039;] \/ 1000 \/ 1000, 1);\n\n$apcuInfo = apcu_cache_info();\n?&gt;\n&lt;style&gt;\n  #stats-box {\n    color: #A9A9A9; \n    text-align: center; \n    margin-top: -10px; \n    padding-bottom: 10px; \n    font-size: 12px;\n    font-family: Roboto,Verdana;\n  }\n&lt;\/style&gt;\n&lt;div id=&quot;stats-box&quot;&gt;\n  Generiert in &lt;?=$totalExecutionTime?&gt;ms mit &lt;?=$filesCount?&gt; Dateien, &lt;?=$memory?&gt; KB Arbeitsspeicher (Real: &lt;?=$realMemory?&gt; KB), Spitze: &lt;?=$peakMemory?&gt; KB (Real: &lt;?=$realPeakMemory?&gt; KB)&lt;br \/&gt;\n  OPCache: &lt;?=$opcache[&#039;opcache_statistics&#039;][&#039;num_cached_scripts&#039;]?&gt; Skripte, &lt;?=$opcache[&#039;opcache_statistics&#039;][&#039;hits&#039;]?&gt; Hits, &lt;?=$opcache[&#039;opcache_statistics&#039;][&#039;misses&#039;]?&gt; Misses, Hit-Rate: &lt;?=round($opcache[&#039;opcache_statistics&#039;][&#039;opcache_hit_rate&#039;], 1)?&gt;% &lt;br \/&gt;\n  APU: &lt;?=$apcuAvailable?&gt; MB von &lt;?=$apcuSize?&gt; MB verf\u00fcgbar | &lt;?=$apcuInfo[&#039;num_entries&#039;]?&gt;\/&lt;?=$apcuInfo[&#039;num_slots&#039;]?&gt; Slots verwendet | &lt;?=$apcuInfo[&#039;num_hits&#039;]?&gt; Hits, &lt;?=$apcuInfo[&#039;num_misses&#039;]?&gt; Misses<\/code><\/pre>\n<p><strong>Hinweis<\/strong>: Jeder <code class=\"\" data-line=\"\">apcu_exists()<\/code> Aufruf wird als Cache-Hit gewertet! Daher generiert obiges Skript pro Ladevorgang zwei Hits. <\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-23_20-25.avif\"><img loading=\"lazy\" decoding=\"async\" width=\"634\" height=\"136\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-23_20-25.avif\" alt=\"\" class=\"wp-image-16550\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-23_20-25.avif 634w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-23_20-25-300x64.avif 300w\" sizes=\"auto, (max-width: 634px) 100vw, 634px\" \/><\/a><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\">\u00dcbersicht &amp; Analyse per Skript<\/h2>\n<p>Mit dem php-cache-dashboard existiert ein simples Skript, welches zur \u00dcbersicht \u00fcber den gesamten Cache ideal ist.<sup data-fn=\"89ae0983-ff58-4af0-9daf-dc9e00f90075\" class=\"fn\"><a href=\"#89ae0983-ff58-4af0-9daf-dc9e00f90075\" id=\"89ae0983-ff58-4af0-9daf-dc9e00f90075-link\">1<\/a><\/sup> Es besteht aus einer einzigen PHP-Datei (cache.php), sodass es ohne gro\u00dfartige Installation leicht abgelegt &amp; sp\u00e4ter wieder entfernt werden kann. Angezeigt wird Opcache, APC (PHP &lt; 5.5)\/APCu (ab 5.5) und sogar der Realpath-Zwischenspeicher. Auch Redis als externe, verteilte L\u00f6sung wird abgefragt. Die Auslastung ist grafisch dargestellt. Auf Wunsch zeigt das Skript die zwischengespeicherten Dateien als Tabelle mit Meta-Infos (Hits, Gr\u00f6\u00dfe). Au\u00dferdem lassen sich die derzeit abgelegten Schl\u00fcssel mit ihren Werten anzeigen sowie durchsuchen. F\u00fcr Tests k\u00f6nnen einzelne Schl\u00fcssel oder der ganze Cache geleert werden. Damit eignet es sich besonders gut f\u00fcr Anwendungen, in denen man eine \u00dcbersicht nicht selbst integrieren kann oder m\u00f6chte &#8211; etwa ein CMS.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_18-18.avif\"><img loading=\"lazy\" decoding=\"async\" width=\"966\" height=\"655\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_18-18.avif\" alt=\"\" class=\"wp-image-16616\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_18-18.avif 966w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_18-18-300x203.avif 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_18-18-768x521.avif 768w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_18-18-531x360.avif 531w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2026\/02\/2026-02-26_18-18-251x170.avif 251w\" sizes=\"auto, (max-width: 966px) 100vw, 966px\" \/><\/a><\/figure>\n<\/div>\n<p><strong>Achtung<\/strong>: Da php-cache-dashboard auch das L\u00f6schen des Zwischenspeichers erm\u00f6glicht, sollte man es m\u00f6glichst nicht (dauerhaft) ungesch\u00fctzt \u00f6ffentlich erreichbar zug\u00e4nglich machen.<\/p>\n<p>Unabh\u00e4ngig von der Datenquelle sollte man nach einiger Zeit der produktiven Nutzung die Auslastung des Cache pr\u00fcfen. Je nach Anwendung l\u00e4sst sich der reservierte Speicher deutlich verkleinern. Oder er ist zu knapp bemessen, wodurch nur ein Teil seines Potenzials nutzbar ist.<\/p>\n<h2 class=\"wp-block-heading\">Weitere Einstellungen<\/h2>\n<p>Ein Blick in die Dokumentation lohnt sich. Dort sind alle OPcache Direktiven mit ihren Standardwerten dokumentiert. Klickt man darauf, folgt weiter unten eine Erkl\u00e4rung.<sup data-fn=\"1d507705-21be-4abc-9bf8-186e946d5126\" class=\"fn\"><a href=\"#1d507705-21be-4abc-9bf8-186e946d5126\" id=\"1d507705-21be-4abc-9bf8-186e946d5126-link\">2<\/a><\/sup> Selbiges gilt f\u00fcr APCu.<sup data-fn=\"74f0608f-5fa0-4c30-8285-41755e0ef31e\" class=\"fn\"><a href=\"#74f0608f-5fa0-4c30-8285-41755e0ef31e\" id=\"74f0608f-5fa0-4c30-8285-41755e0ef31e-link\">3<\/a><\/sup> Dort finden sich zudem Hilfsfunktionen wie <code class=\"\" data-line=\"\">apcu_inc\/apcu_dec<\/code>: Sie k\u00f6nnen Werte zu Variablen hinzu z\u00e4hlen. Das vereinfacht den Umgang mit Z\u00e4hlern, weil man sich die obige Logik <em>Laden wenn vorhanden\/andernfalls abspeichern<\/em> spart.<\/p>\n<p>Folgende Direktiven k\u00f6nnen f\u00fcr manche interessant sein:<\/p>\n<ul class=\"wp-block-list\">\n<li>Ist <code class=\"\" data-line=\"\">opcache.validate_timestamps<\/code> aktiv (1), pr\u00fcft PHP alle <code class=\"\" data-line=\"\">opcache.revalidate_freq<\/code> Sekunden, ob sich die Zwischengespeicherten Skripte ge\u00e4ndert haben (standardm\u00e4\u00dfig alle 2s).<\/li>\n<li>opcache.save_comments speichert Kommentare, wenn aktiv (Standard). Wird diese Option abgeschaltet, sinkt der Speicherbedarf des Caches. Allerdings kann es zu Problemen mit bestimmten Frameworks kommen, die Kommentare intern verwenden (z.B. Doctrine oder PHPUnit).<\/li>\n<li>Ist ein Pfad f\u00fcr opcache.file_cache gesetzt, legt PHP dort den Cache zus\u00e4tzlich im Dateisystem an. Oder sollte es zumindest, ich habe es zusammen mit <code class=\"\" data-line=\"\">mod_php<\/code> nicht zum Laufen bekommen. Relevant sollen hierbei <code class=\"\" data-line=\"\">opcache.validate_timestamps<\/code> und <code class=\"\" data-line=\"\">opcache.revalidate_freq<\/code> sein, da sie standardm\u00e4\u00dfig zur schnellen L\u00f6schung f\u00fchren.<\/li>\n<\/ul>\n<h2 class=\"wp-block-heading\">Fehlersuche<\/h2>\n<p>Bei der Analyse\/Fehlersuche bez\u00fcglich des OPcache kann <code class=\"\" data-line=\"\">opcache.log_verbosity_level=4<\/code> helfen (2 = Warnungen, Informationen = 3, Debug = 4): Es schreibt Informationen ins Log, wenn beispielsweise ein bisher nicht im Cache liegendes Skript (<em>Cache Miss<\/em>) dort abgelegt wird.<\/p>\n<p>Ebenfalls n\u00fctzlich ist die M\u00f6glichkeit, per <code class=\"\" data-line=\"\">php -i<\/code> s\u00e4mtliche Konfigurationseinstellungen ausgeben zu k\u00f6nnen. Der altbekannte Weg \u00fcber ein Skript mit dem Inhalt <code class=\"\" data-line=\"\">&lt;?php phpinfo();<\/code> mag eben so funktionieren. Ich finde die Kommandozeile eleganter: Dadurch ist nicht die komplette PHP-Info \u00f6ffentlich erreichbar, sofern es sich um einen Server im WWW handelt. Au\u00dferdem kann sie geschickt mit <code class=\"\" data-line=\"\">grep<\/code> durchsucht werden.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$ docker compose exec -it opcache-demo php -i | grep opcache.enable\nopcache.enable =&gt; On =&gt; On\nopcache.enable_cli =&gt; Off =&gt; Off\nopcache.enable_file_override =&gt; Off =&gt; Off<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Quellen<\/h2>\n<ol class=\"wp-block-footnotes\">\n<li id=\"89ae0983-ff58-4af0-9daf-dc9e00f90075\"><a href=\"https:\/\/github.com\/JorgenEvens\/php-cache-dashboard\" target=\"_blank\" rel=\"nofollow\">https:\/\/github.com\/JorgenEvens\/php-cache-dashboard<\/a> <a href=\"#89ae0983-ff58-4af0-9daf-dc9e00f90075-link\" aria-label=\"Zur Fu\u00dfnotenreferenz 1 navigieren\">\u21a9\ufe0e<\/a><\/li>\n<li id=\"1d507705-21be-4abc-9bf8-186e946d5126\"><a href=\"https:\/\/www.php.net\/manual\/en\/opcache.configuration.php\" target=\"_blank\" rel=\"nofollow\">https:\/\/www.php.net\/manual\/en\/opcache.configuration.php<\/a> <a href=\"#1d507705-21be-4abc-9bf8-186e946d5126-link\" aria-label=\"Zur Fu\u00dfnotenreferenz 2 navigieren\">\u21a9\ufe0e<\/a><\/li>\n<li id=\"74f0608f-5fa0-4c30-8285-41755e0ef31e\"><a href=\"https:\/\/www.php.net\/manual\/en\/apcu.configuration.php\" target=\"_blank\" rel=\"nofollow\">https:\/\/www.php.net\/manual\/en\/apcu.configuration.php<\/a> <a href=\"#74f0608f-5fa0-4c30-8285-41755e0ef31e-link\" aria-label=\"Zur Fu\u00dfnotenreferenz 3 navigieren\">\u21a9\ufe0e<\/a><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Wie muss eine PHP-Installation aussehen, um von den zahlreichen Performance-Verbesserungen (v.a. Caching) der letzten Versionen zu profitieren? Dieser Beitrag demonstriert das an einer praktischen Umgebung, welche direkt f\u00fcr eigene Anwendungen oder dem Betreiben von Drittanbieter-Anwendungen genutzt werden kann. Darauf liegt der Fokus: Beispiele, die sich direkt ausprobieren sowie einsetzen lassen. Auf die Funktion &amp; Hintergr\u00fcnde &#8230;<\/p>\n","protected":false},"author":5,"featured_media":16914,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"[{\"content\":\"<a href=\\\"https:\/\/github.com\/JorgenEvens\/php-cache-dashboard\\\">https:\/\/github.com\/JorgenEvens\/php-cache-dashboard<\/a>\",\"id\":\"89ae0983-ff58-4af0-9daf-dc9e00f90075\"},{\"content\":\"<a href=\\\"https:\/\/www.php.net\/manual\/en\/opcache.configuration.php\\\">https:\/\/www.php.net\/manual\/en\/opcache.configuration.php<\/a>\",\"id\":\"1d507705-21be-4abc-9bf8-186e946d5126\"},{\"content\":\"<a href=\\\"https:\/\/www.php.net\/manual\/en\/apcu.configuration.php\\\">https:\/\/www.php.net\/manual\/en\/apcu.configuration.php<\/a>\",\"id\":\"74f0608f-5fa0-4c30-8285-41755e0ef31e\"}]"},"categories":[61],"tags":[497,55],"class_list":["post-16681","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-softwareentwicklung","tag-docker","tag-php"],"_links":{"self":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/16681","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/comments?post=16681"}],"version-history":[{"count":6,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/16681\/revisions"}],"predecessor-version":[{"id":16919,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/16681\/revisions\/16919"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media\/16914"}],"wp:attachment":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media?parent=16681"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/categories?post=16681"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/tags?post=16681"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}