Signatur
Beschreibung
apcu_cas implementiert eine atomare Compare-and-Swap-Operation auf dem APCu-Cache. Der unter $key gespeicherte Wert wird nur dann auf $new geändert, wenn er aktuell exakt dem Wert $old entspricht. Diese Atomarität verhindert Race Conditions, die bei einer gewöhnlichen Lese-Prüf-Schreib-Abfolge entstehen könnten.
Die Funktion ist besonders nützlich in nebenläufigen Umgebungen (z. B. bei mehreren PHP-FPM-Prozessen), wenn ein gemeinsam genutzter Zähler oder ein Statuswert im Cache nur dann aktualisiert werden soll, wenn kein anderer Prozess ihn zwischenzeitlich verändert hat. Typische Anwendungsfälle sind Mutex-ähnliche Sperrmechanismen, Zähler und Versionsverwaltung im Cache.
Wichtig: Sowohl $old als auch $new müssen Integer-Werte sein. Für String- oder Array-Werte muss auf alternative Strategien zurückgegriffen werden. Schlägt der Tausch fehl (weil der aktuelle Wert nicht $old entspricht oder der Schlüssel nicht existiert), wird false zurückgegeben — ohne eine Exception zu werfen.
Da apcu_cas ein nicht blockierendes Primitiv ist, empfiehlt sich bei Bedarf eine Retry-Schleife, die mehrfach versucht, den Swap erfolgreich durchzuführen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $key Pflicht | string | Der Schlüssel des APCu-Eintrags, dessen Wert atomar ausgetauscht werden soll. | |
| $old Pflicht | int | Der erwartete aktuelle Wert im Cache. Der Tausch findet nur statt, wenn der gespeicherte Wert exakt diesem Integer entspricht. | |
| $new Pflicht | int | Der neue Integer-Wert, auf den der Cache-Eintrag gesetzt werden soll, wenn $old übereinstimmt. |
Rückgabewert
true zurück, wenn der Tausch erfolgreich war (der gespeicherte Wert entsprach $old und wurde auf $new gesetzt). Gibt false zurück, wenn der Wert nicht übereinstimmte, der Schlüssel nicht existiert oder APCu nicht verfügbar ist.Beispiele
Einfacher Compare-and-Swap eines Zählers
<?php
// Zähler initialisieren
apcu_store('counter', 5);
// Atomarer Tausch: nur wenn der Wert noch 5 ist, wird er auf 6 gesetzt
$success = apcu_cas('counter', 5, 6);
if ($success) {
echo 'Wert erfolgreich von 5 auf 6 geändert.';
} else {
echo 'Tausch fehlgeschlagen – Wert wurde bereits geändert.';
}
echo PHP_EOL . 'Aktueller Wert: ' . apcu_fetch('counter');
Retry-Schleife für konkurrierenden Zugriff
<?php
// Gemeinsamen Zustand initialisieren
apcu_store('status', 0);
// Versuche, Status von 0 auf 1 zu setzen (mit Retry bei Konkurrenz)
$maxRetries = 10;
$switched = false;
for ($i = 0; $i < $maxRetries; $i++) {
$current = apcu_fetch('status');
if ($current === false) {
echo 'Schlüssel nicht vorhanden.';
break;
}
if (apcu_cas('status', $current, $current + 1)) {
$switched = true;
echo "Wert erfolgreich von {$current} auf " . ($current + 1) . " erhöht.";
break;
}
// Kurze Pause vor erneutem Versuch
usleep(100);
}
if (!$switched) {
echo 'Konnte Wert nach ' . $maxRetries . ' Versuchen nicht aktualisieren.';
}
// Wichtig · Fallstricke
Nur Integer: apcu_cas funktioniert ausschließlich mit Integer-Werten. Wird ein Schlüssel mit einem anderen Typ (z. B. String oder Array) gespeichert, schlägt die Operation fehl und gibt false zurück.
Existenz des Schlüssels: Existiert der Schlüssel gar nicht im Cache, wird ebenfalls false zurückgegeben. Ein vorheriges apcu_store oder apcu_add ist erforderlich.
CLI-Umgebung: APCu ist in der PHP-CLI standardmäßig deaktiviert. Für Tests in der Konsole muss apc.enable_cli=1 in der php.ini gesetzt werden.
Kein Ersatz für vollwertige Locks: Für komplexe kritische Abschnitte empfiehlt sich ein dediziertes Locking-System (z. B. apcu_add als Mutex-Primitiv oder Redis-basierte Locks).