# OPcache förklarat: PHP:s bytekodcache

> OPcache förklarat: så arbetar PHP:s bytekodcache, vilka inställningar som räknas, varför den måste tömmas efter uppdateringar och hur ni säkrar den.

Källa: https://phpsos.de/sv/php/opcache/  
Aktualitet: 2026-10-25  
Leverantör: PHP SOS, PHP-nödhjälp och serversäkerhet. Omedelbar hjälp via WhatsApp: https://wa.me/491736494914?text=Hej%20PHP%20SOS%2C%20vi%20beh%C3%B6ver%20hj%C3%A4lp%20med%20v%C3%A5r%20PHP-server.%20F%C3%B6retag%3A%20%E2%80%A6%20Webbplats%3A%20%E2%80%A6

**Kort sagt:** OPcache är PHP:s inbyggda bytekodcache. Enligt manualen lagrar den förkompilerad bytekod i delat minne, så att PHP inte behöver läsa in och översätta skript vid varje förfrågan. Den ingår i leveransen sedan PHP 5.5.0. OPcache gör PHP snabbare men ersätter ingen uppdatering: Efter en PHP-patch måste alla PHP-processer startas om, det räcker inte att tömma cachen.

## Vad gör OPcache egentligen?

Vid varje förfrågan måste PHP läsa ett skript, dela upp det och översätta det till opcodes, alltså kommandona för den virtuella maskinen i [Zend Engine](https://phpsos.de/sv/php/zend-engine/). För ett CMS med hundratals filer är det mycket arbete som ständigt upprepas.

OPcache lagrar resultatet av den översättningen i delat minne (shared memory). Alla workers i en PHP-FPM-tjänst eller alla Apache-processer med mod_php använder det. Ändras en fil inte återanvänds dess bytekod direkt.

OPcache laddas som Zend-tillägg, inte som ett vanligt tillägg:

```ini
; Linux (sökväg beroende på paket)
zend_extension=opcache.so
; Windows
; zend_extension=php_opcache.dll
```

Enligt manualen ska OPcache laddas före Xdebug om båda är aktiva.

Vem som äger det delade minnet är viktigt. Med PHP-FPM skapar masterprocessen det, och alla workers i alla pooler i den tjänsten använder det. Med mod_php hör det till Apache-huvudprocessen. En omstart av tjänsten tömmer därför cachen helt, medan en enskild ny worker inte gör det. För kommandoraden finns inget delat minne mellan anropen, eftersom varje anrop är en egen process; där är OPcache som standard avstängd.

För beslutsfattare räcker en tumregel: OPcache är på produktionsservrar nästan alltid meningsfull men kräver ett tydligt förfarande för driftsättningar och uppdateringar.

## Vilka OPcache-inställningar räknas?

Följande värden kommer från konfigurationssidan i PHP-manualen. Kolumnen ”Ändringsbar” visar var en inställning får sättas: `INI_SYSTEM` bara i php.ini eller serverkonfigurationen, `INI_ALL` överallt.

| Direktiv | Standard | Ändringsbar | Betydelse |
|---|---|---|---|
| `opcache.enable` | 1 | INI_ALL | cache på eller av, vid körning går den bara att stänga av |
| `opcache.enable_cli` | 0 | INI_SYSTEM | cache för kommandoraden |
| `opcache.memory_consumption` | 128 | INI_SYSTEM | storlek på det delade minnet i MB |
| `opcache.interned_strings_buffer` | 8 | INI_SYSTEM | minne för gemensamma teckensträngar i MB |
| `opcache.max_accelerated_files` | 10000 | INI_SYSTEM | maximalt antal cachade skript |
| `opcache.validate_timestamps` | 1 | INI_ALL | kontrollerar om filer har ändrats |
| `opcache.revalidate_freq` | 2 | INI_ALL | kontrollintervall i sekunder, 0 = vid varje förfrågan |
| `opcache.restrict_api` | tom | INI_SYSTEM | tillåter API-funktioner bara från en viss sökväg |
| `opcache.validate_permission` | 0 | INI_SYSTEM | kontrollerar filrättigheter mot aktuell användare |
| `opcache.validate_root` | 0 | INI_SYSTEM | förhindrar namnkollisioner vid chroot |
| `opcache.file_cache` | tom | INI_SYSTEM | andra cachenivå på disken |

En typisk produktionskonfiguration kan se ut så här. Kontrollera värdena med er applikation i förväg:

```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
```

Den som sätter `opcache.validate_timestamps=0` vinner lite prestanda. Då upptäcker OPcache dock inte längre ändrade filer alls, och varje driftsättning kräver en återställning av cachen eller en omstart.

## Iaktta cachen och tömma den riktat

OPcache har egna funktioner, bland annat `opcache_get_status()`, `opcache_get_configuration()`, `opcache_invalidate()` och `opcache_reset()`. En kort, enbart läsande titt på fyllnadsgraden:

```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);
```

På servrar med flera webbplatser bör inte varje applikation kunna tömma eller läsa ut alla andras cache. Det är vad `opcache.restrict_api` är till för: Bara skript under den angivna sökvägen får anropa API-funktionerna.

## JIT: maskinkodskompilatorn i OPcache

Sedan PHP 8.0 innehåller OPcache en JIT-kompilator som översätter opcodes till maskinkod. Enligt JIT-RFC:t är den en nästan fristående del av OPcache och lägger den skapade koden i ett eget område i det delade minnet. Den styrs med `opcache.jit` och `opcache.jit_buffer_size`. Sedan PHP 8.4.0 står `opcache.jit` som standard på `disable`. När JIT lönar sig förklaras i artikeln [JIT och prestanda i PHP 8](https://phpsos.de/sv/php/jit-und-performance/).

## OPcache och säkerhet: vad som gäller efter PHP2Shell

OPcache är inget säkerhetsverktyg men får konsekvenser för säkerheten. Tre punkter är viktiga efter PHP2Shell:

1. **En cache-återställning är ingen uppdatering.** `opcache_reset()` tömmer bara cachade skript. Tolken med sårbarheterna CVE-2026-109618 och CVE-2026-109619 finns kvar i minnet tills alla processer har startats om. Hur det går till står under [Starta om PHP-FPM och alla workers](https://phpsos.de/sv/php2shell/php-fpm-neustart/).
2. **Insmugglad kod kan leva vidare i cachen.** Om en fil har manipulerats och senare ersatts kan den gamla versionen fortsätta köras när tidsstämpelkontrollen är avstängd. Efter en sanering hör därför en omstart till.
3. **Delat minne kräver åtskillnad.** På servrar med flera kunder hjälper egna PHP-FPM-pooler per webbplats samt `opcache.validate_permission` och `opcache.restrict_api`. En katalog för `opcache.file_cache` får bara vara skrivbar för PHP-användaren.

> **Tips:**
> Kontrollera efter varje uppdatering att PHP-processernas starttid ligger efter uppdateringen. En full OPcache med hög träffprocent är inget bevis för att den nya tolken körs.

## Hur hjälper PHP SOS konkret?

- **Kontrollera konfigurationen:** Vi läser ut den aktiva OPcache-konfigurationen per driftläge och jämför den med er applikation.
- **Säkra driftsättningar:** Vi inför ett fast förfarande för cache-återställning och omstart, så att ingen gammal kodversion fortsätter att köras.
- **Skilja mandanter åt:** Inom ramen för [serverhärdning](https://phpsos.de/sv/leistungen/server-haertung/) sätter vi åtskilda pooler, `restrict_api` och lämpliga rättigheter.
- **Kontrollera efter uppdateringar:** Vi styrker via processernas starttider att den uppdaterade tolken verkligen är aktiv.


## Vanliga frågor

**Är OPcache aktiv som standard?**  
OPcache levereras med PHP sedan PHP 5.5.0 och körs enligt manualen med opcache.enable=1 som standard så snart tillägget är laddat. Om det är laddat beror på ert paket eller webbhotell. På kommandoraden är OPcache däremot som standard avstängd (opcache.enable_cli=0).

**Varför ser jag fortfarande den gamla koden efter en driftsättning?**  
Troligen kontrollerar OPcache filändringar bara med intervall eller inte alls. Med opcache.revalidate_freq väntar den som standard två sekunder, med opcache.validate_timestamps=0 aldrig. Då hjälper bara en återställning av cachen eller en omstart av PHP-FPM respektive Apache.

**Räcker opcache_reset() efter en PHP-uppdatering?**  
Nej. opcache_reset() tömmer bara cachen med översatta skript. En PHP-uppdatering ersätter själva tolken, och den är laddad i varje pågående process. Därför måste alla PHP-processer startas om.

**Är JIT påslagen i PHP 8.4?**  
Enligt manualen är opcache.jit sedan PHP 8.4.0 som standard satt till disable, medan opcache.jit_buffer_size är 64M. Tidigare var det tvärtom: jit på tracing, buffert på 0. I båda fallen är JIT inte aktiv utan medveten konfiguration.

## Källor

- [PHP-manualen: OPcache](https://www.php.net/manual/en/book.opcache.php)
- [PHP-manualen: OPcache-konfiguration](https://www.php.net/manual/en/opcache.configuration.php)
- [PHP-manualen: OPcache-installation](https://www.php.net/manual/en/opcache.installation.php)
- [PHP RFC: JIT](https://wiki.php.net/rfc/jit)
