Start · Sprachen · PHP · Referenz · apcu_cas

apcu_cas

Funktion

Ersetzt einen Wert im APCu-Cache atomar, wenn er einem erwarteten alten Wert entspricht (Compare-and-Swap).

seit PHP 4.0.0 Kategorie: misc

Signatur

apcu_cas(string $key, int $old, int $new): bool

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

Typ
bool
Beschreibung
Gibt 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');
Wert erfolgreich von 5 auf 6 geändert. Aktueller Wert: 6

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.';
}
Wert erfolgreich von 0 auf 1 erhöht.

// 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).