phpbotgram

StatesGroup
in package

AbstractYes

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')true
  • Form::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
see
State
States

for the module-level default_state / any_state equivalents.

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 — checks allStateNames().
  • State — checks allStates().
  • class string — checks allChildren().

Mirrors StatesGroup.__contains__ (aiogram/fsm/state.py:145-153).

Parameters
$item : StatesGroup>|State|string
Return values
bool

fullGroupName()

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
string

getRoot()

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>|bool

extractShortName()

Return the short (unqualified) class name.

private static extractShortName(class-string $class) : string

Foo\Bar\MyGroup'MyGroup'.

Parameters
$class : class-string
Return values
string
On this page

Search results