ADR 0001: Actor Model Architecture for PHP
Status
Accepted
Context
PHP lacks a structured concurrency model for building long-running, message-driven systems. Current approaches rely on ad-hoc queue workers, process managers, and manual error recovery. The actor model — proven in Erlang/OTP and Akka — provides a principled foundation: isolated units of computation that communicate only via asynchronous messages, with hierarchical supervision for fault tolerance.
PHP 8.5 introduces features (readonly class, pipe operator, #[NoDiscard]) that make a type-safe actor implementation viable. The question is whether to build a full actor system or a simpler message-passing library.
Decision
Build a full actor system with:
- Actor hierarchy: Every actor has a parent. The root is the
ActorSystemguardian. - Message-driven: Actors communicate exclusively via immutable messages through typed
ActorRef<T>. - Location transparency:
ActorRefabstracts whether the actor is local or remote. - Supervision: Parent actors define strategies for child failures (restart, stop, escalate).
- Runtime abstraction: The actor system is decoupled from the execution engine via a
Runtimeinterface, allowing different concurrency backends.
The architecture follows Akka's typed actor model rather than Erlang's process model, because PHP's type system (with Psalm generics) can enforce message type safety at analysis time.
Consequences
- Actors must be spawned through the system hierarchy (no standalone actors).
- All state is private to the actor; shared mutable state is impossible by design.
- The
Runtimeinterface must support scheduling, timers, and mailbox creation. - Message types must be
readonly classto prevent accidental mutation. - Psalm generic templates are required for type-safe
ActorRef<T>andBehavior<T>.