StatesGroup
in package
Abstract base class for a named group of related FSM states.
Mirrors aiogram.fsm.state.StatesGroup (implemented via the
StatesGroupMeta metaclass in aiogram/fsm/state.py:89-180).
Why bootstrap instead of metaclass
Python's StatesGroupMeta.__new__ runs at class-definition time,
automatically discovering all State class attributes and nested
StatesGroup subclasses. PHP has no equivalent metaclass hook — class
declaration is passive. The PHP port uses explicit bootstrap: the
framework (or user code) must call MyGroup::bootstrap() (or rely on
the defensive bootstrapIfNeeded()) before using the group.
User API
Subclasses declare states as public static typed properties and nested
groups via the CHILDREN class constant:
class Form extends StatesGroup {
public static State $name;
public static State $age;
public const array CHILDREN = [Sub::class];
}
class Sub extends StatesGroup {
public static State $email;
}
Form::bootstrap(); // or let StateFilter call bootstrapIfNeeded()
After bootstrap:
Form::$name->state()→'Form:name'Sub::$email->state()→'Form.Sub:email'Form::contains('Form:name')→trueForm::contains(Sub::class)→true
Per-class static data storage
PHP abstract classes share a single static property namespace with all
subclasses (late-static binding lets static::$prop target the concrete
subclass, but ONLY if $prop is declared in that subclass or redeclared
there). Declaring per-class data as static properties on the abstract
base would cause all subclasses to share the same slot.
The PHP port therefore stores all per-class bootstrap data in the single
static $registry array on the base class, keyed by concrete class name:
self::$registry[ClassName]['fullGroupName'] = '...';
self::$registry[ClassName]['allStates'] = [...];
self::$registry[ClassName]['allStateNames'] = [...];
self::$registry[ClassName]['allChildren'] = [...];
self::$registry[ClassName]['parentGroup'] = ClassName|null;
All accessors (allStates(), fullGroupName(), …) key into this registry
via static::class. Because the registry and every accessor are on the
SAME abstract base class, PHPStan's staticClassAccess.privateMethod rule
is satisfied by calling them via self:: (not static::): every call
site that dispatches via self:: is within the same class where the
private method is declared.
Thread-safety / idempotency
bootstrap() is idempotent: it tracks processed classes in the static
$registry keyed by class name. Multiple calls to bootstrap() for
the same class are harmless.
Tags
Table of Contents
Constants
- CHILDREN : array<string|int, mixed> = []
- Subclasses list nested `StatesGroup` subclasses here.
Properties
- $registry : array<StatesGroup>, array<string, mixed>>
- Per-class bootstrap data store.
Methods
- allChildren() : array<string|int, StatesGroup>>
- Return all direct + transitive child `StatesGroup` class names.
- allStateNames() : array<string|int, string>
- Return all qualified state-name strings for this group and its children.
- allStates() : array<string|int, State>
- Return all `State` instances directly belonging to this group.
- allStatesIncludingNested() : array<string|int, State>
- Return all `State` instances belonging to this group and all nested children.
- bootstrap() : void
- Walk the class via reflection to auto-vivify State instances, bind names and parents, and recurse into children.
- bootstrapIfNeeded() : void
- Call `bootstrap()` exactly once per class; subsequent calls are no-ops.
- contains() : bool
- Test membership of a string state name, a `State` instance, or a `StatesGroup` subclass.
- fullGroupName() : string
- Return the fully-qualified group name (`Parent.Child.GrandChild`).
- getRoot() : StatesGroup>
- Walk the `parentGroup` chain to the topmost group and return its class.
- match() : array<string, mixed>|bool
- Evaluate whether the event is in any state belonging to this group.
- extractShortName() : string
- Return the short (unqualified) class name.
Constants
CHILDREN
Subclasses list nested `StatesGroup` subclasses here.
public
array<string|int, mixed>
CHILDREN
= []
public const array CHILDREN = [Sub::class, AnotherSub::class];
Bootstrap walks this list recursively so that nested groups acquire
the correct fullGroupName() cascade before their states are resolved.
Properties
$registry
Per-class bootstrap data store.
private
static array<StatesGroup>, array<string, mixed>>
$registry
= []
Keys at the first level are concrete subclass names. Each entry holds:
'bootstrapped'→true(presence signals the class is done)'fullGroupName'→string'parentGroup'→class-string<StatesGroup>|null'allStates'→array<State>(direct states only)'allStateNames'→array<string>(direct + all nested)'allChildren'→array<class-string<StatesGroup>>'allStatesIncludingNested'→array<State>(direct + all nested)
Methods
allChildren()
Return all direct + transitive child `StatesGroup` class names.
public
static allChildren() : array<string|int, StatesGroup>>
Return values
array<string|int, StatesGroup>>allStateNames()
Return all qualified state-name strings for this group and its children.
public
static allStateNames() : array<string|int, string>
Derived on each call from the live State objects in
allStatesIncludingNested() so that a child whose parentGroup was
updated after standalone bootstrap emits the correct qualified names.
Mirrors StatesGroup.__all_states_names__ (aiogram/fsm/state.py:126-131).
Return values
array<string|int, string>allStates()
Return all `State` instances directly belonging to this group.
public
static allStates() : array<string|int, State>
Mirrors StatesGroup.__iter__ (aiogram/fsm/state.py:155-157).
Return values
array<string|int, State>allStatesIncludingNested()
Return all `State` instances belonging to this group and all nested children.
public
static allStatesIncludingNested() : array<string|int, State>
Mirrors StatesGroup.__all_states__ (aiogram/fsm/state.py:77, 135-139),
which recursively includes states from all child groups.
Return values
array<string|int, State>bootstrap()
Walk the class via reflection to auto-vivify State instances, bind names and parents, and recurse into children.
public
static bootstrap([null|StatesGroup> $parentClass = null ]) : void
Idempotent: repeated calls for the same class are a no-op.
When a parent bootstraps a child that is already in the registry the
child's parentGroup is updated so that fullGroupName() can walk
the correct chain on the next call.
Mirrors StatesGroupMeta.__new__ (aiogram/fsm/state.py:89-143).
Parameters
- $parentClass : null|StatesGroup> = null
-
When called recursively from a parent group, this is the parent's class name.
bootstrapIfNeeded()
Call `bootstrap()` exactly once per class; subsequent calls are no-ops.
public
static bootstrapIfNeeded() : void
Framework-defensive entry point — called by StateFilter before reading
any group metadata, so that user code that omits the explicit bootstrap()
call still works.
contains()
Test membership of a string state name, a `State` instance, or a `StatesGroup` subclass.
public
static contains(StatesGroup>|State|string $item) : bool
string— checksallStateNames().State— checksallStates().- class string — checks
allChildren().
Mirrors StatesGroup.__contains__ (aiogram/fsm/state.py:145-153).
Parameters
- $item : StatesGroup>|State|string
Return values
boolfullGroupName()
Return the fully-qualified group name (`Parent.Child.GrandChild`).
public
static fullGroupName() : string
Computed dynamically by walking the parentGroup chain so that a child
bootstrapped standalone and later claimed by a parent reflects the correct
qualified prefix on the very next call — no stale cached value.
Mirrors StatesGroup.__full_group_name__ (aiogram/fsm/state.py:117-120).
Return values
stringgetRoot()
Walk the `parentGroup` chain to the topmost group and return its class.
public
static getRoot() : StatesGroup>
Mirrors StatesGroup.get_root() (aiogram/fsm/state.py:160-168).
Return values
StatesGroup>match()
Evaluate whether the event is in any state belonging to this group.
public
static match(object $event, mixed ...$kwargs) : array<string, mixed>|bool
Reads $kwargs['raw_state'] ?? null (snake_case, matching
FsmContextMiddleware::RAW_STATE_KEY) and returns true when that
value is in allStateNames().
Mirrors StatesGroup.__call__ (aiogram/fsm/state.py:154-157).
Parameters
- $event : object
- $kwargs : mixed
Return values
array<string, mixed>|boolextractShortName()
Return the short (unqualified) class name.
private
static extractShortName(class-string $class) : string
Foo\Bar\MyGroup → 'MyGroup'.
Parameters
- $class : class-string