Shared\Flag
OxPHP\Shared\Flag est un booléen atomique à l'échelle du processus — le jumeau booléen de Shared\Atomic. Chaque opération est sans verrou ; deux workers qui inversent le drapeau simultanément ne peuvent pas observer d'état intermédiaire.
Vue d'ensemble
- Booléen atomique. Un seul bit d'état, avec
load/store/swap/compareAndSet. - Ordonnancement mémoire explicite. Chaque opération accepte un
Orderingoptionnel, dont la valeur par défaut estSeqCst, exactement commeShared\Atomic. - Sans verrou. Toutes les mutations tiennent en une seule instruction atomique du CPU. Sûr en cas de contention.
- Partageable. Les instances vivent dans le registre et peuvent être stockées dans un
Shared\Map, transmises via des capturesuse, etc.
Référence de l'API
namespace OxPHP\Shared;
final class Flag implements Shareable
{
public function __construct(bool $initial = false);
public function load(Ordering $order = Ordering::SeqCst): bool; // Relaxed | Acquire | SeqCst
public function store(bool $value, Ordering $order = Ordering::SeqCst): void; // Relaxed | Release | SeqCst
public function swap(bool $value, Ordering $order = Ordering::SeqCst): bool; // any ordering; returns previous
public function compareAndSet(
bool $expect,
bool $new,
Ordering $success = Ordering::SeqCst,
Ordering $failure = Ordering::SeqCst, // Relaxed | Acquire | SeqCst
): bool;
public function id(): int;
}| Méthode | Retour | Cas d'usage |
|---|---|---|
load |
actuelle | Simple lecture. |
store |
void | Affecte une valeur explicite sans condition. |
swap |
précédente | Affecte une valeur explicite ; la valeur de retour indique si vous l'avez modifiée. swap(true) est un test-and-set (« ai-je gagné ? »). |
compareAndSet |
échangé ? | Initialisation one-shot : ne réussit que si le drapeau valait la valeur attendue. |
Exemples
Kill-switch
<?php
use OxPHP\Shared\Flag;
$maintenance = new Flag();
// In a request handler
if ($maintenance->load()) {
http_response_code(503);
header('Retry-After: 60');
echo 'under maintenance';
return;
}
// In an admin endpoint
$maintenance->store(true); // enable
$maintenance->store(false); // disableVainqueur de l'initialisation one-shot
<?php
use OxPHP\Shared\Flag;
$migrated = new Flag();
if ($migrated->compareAndSet(expect: false, new: true)) {
// First worker to arrive wins — run the migration once.
runSchemaMigration();
} else {
// Someone else already ran it.
}Déclenchement du circuit breaker
<?php
use OxPHP\Shared\Flag;
$tripped = new Flag();
try {
callDownstream();
} catch (DownstreamFailedException $e) {
$wasAlreadyTripped = $tripped->swap(true); // set true, learn the prior state
if (!$wasAlreadyTripped) {
alertOncall($e); // fire alert only on first trip
}
throw $e;
}Pour un circuit breaker complet, vous aurez généralement besoin d'un Shared\Counter pour la fenêtre d'échecs et d'un Shared\Flag pour l'état déclenché — réinitialisez le drapeau via store(false) une fois que la fenêtre est retombée au calme.
Publier une charge utile, puis signaler avec un ordonnancement moins coûteux
<?php
use OxPHP\Shared\Flag;
use OxPHP\Shared\Map;
use OxPHP\Shared\Ordering;
$ready = new Flag();
$config = new Map();
// Producer: write the payload, then publish with Release.
$config->set('dsn', $dsn);
$ready->store(true, Ordering::Release);
// Consumer: an Acquire load that observes `true` also observes the payload.
if ($ready->load(Ordering::Acquire)) {
$dsn = $config->get('dsn');
}Sémantique et pièges
swap renvoie la valeur précédente, qui est le retour le plus utile : « ai-je changé quelque chose ? » se résume à $prev !== $new, et swap(true) est le test-and-set canonique. store renvoie void ; si vous avez besoin de la valeur antérieure, utilisez swap.
compareAndSet est la façon d'exprimer « le premier arrivé l'emporte ». Un simple store(true) réussit toujours, il ne peut donc pas exprimer « ne pas écraser si la valeur est déjà définie ».
L'ordonnancement mémoire est identique à celui de Shared\Atomic. load rejette Release/AcqRel, store rejette Acquire/AcqRel, et le $failure de compareAndSet rejette Release/AcqRel — chacun lève une InvalidOrderingException. La valeur par défaut SeqCst est toujours sûre.
Un drapeau ne bloque pas. Si vous devez attendre une transition, associez-le à un Shared\Channel ou utilisez Shared\Once.
Exceptions
| Exception | Levée par |
|---|---|
StaleHandleException |
Toute méthode sur un handle dont l'entrée de registre a été évincée. |
UninitializedException |
id() sur un wrapper dont le __construct n'est pas terminé. |
InvalidOrderingException |
Un Ordering non autorisé pour l'opération (voir ci-dessus). |
Observabilité
Voir Observabilité de l'état partagé. Références rapides :
GET /__ox_shared/entry?id=Nexpose{ value: true|false, type: "Flag" }.- Jauge Prometheus
oxphp_shared_flag_value{flag_id="…"}(0 ou 1). - Les métriques à l'échelle du registre couvrent Flag via le label
type="Flag".
Quand ne pas l'utiliser
- Logique à plusieurs états. Un drapeau n'a que deux valeurs. S'il vous faut idle/busy/done ou toute machine à trois états, tournez-vous vers
Shared\Counter(avec des valeurs d'enum entières) ouShared\Mutexsur un tableau façon enum. - Attendre une transition. Les drapeaux ne bloquent pas. Associez-le à un
Shared\Channel(ou à unShared\Counterque vous interrogez parcompareAndSet) lorsqu'un worker doit attendre que le drapeau s'inverse. - Compter des événements. Un drapeau n'est pas un compteur. Utilisez
Shared\Counterpour les décomptes. - État entier. Si le commutateur est en réalité un petit entier, utilisez directement
Shared\Atomic.
Prompts pour votre agent
Ces prompts supposent un agent connecté au serveur MCP de la documentation OxPHP — il lira lui-même les pages dont il a besoin.
Utilise un Shared Flag d'OxPHP dans mon code à la place de l'interrupteur de mode maintenance ou de circuit breaker que je garde aujourd'hui dans une variable d'environnement ou un fichier de configuration. Lis la page `shared-state/shared-flag` via le serveur MCP de la documentation OxPHP.
Trouve cet interrupteur dans ce dépôt et montre-moi le remplacement par un Flag, plus le seul point d'appel qui devrait être un `compareAndSet` plutôt qu'un `store` inconditionnel.Voir aussi
- État partagé — vue d'ensemble et modèle mental.
- Shared\Atomic — le jumeau int64, même modèle d'ordonnancement.
- Shared\Counter — quand vous avez besoin de plus que on/off.
- Shared\Once — quand la valeur calculée une seule fois est plus riche qu'un booléen.
- Shared\Mutex — quand l'inversion d'un drapeau doit être validée conjointement avec un autre état.