Scene
in package
Abstract base for all scene classes in the Scene subsystem.
A scene encapsulates a logical conversation step — the user is "in" a
scene while the FSM state matches the scene's declared state. Subclasses
declare their FSM state via the #[SceneState] class attribute and attach
handlers via the #[On*] method attributes (OnMessage, OnCallbackQuery,
etc. in Scene/Attribute/).
Mirrors Scene (aiogram/fsm/scene.py:297-441).
Usage
#[SceneState('greeting')] final class GreetingScene extends Scene { #[OnMessage] public function onMessage(object $message): void { // ... }
#[OnMessage(action: SceneAction::Enter)]
public function onEnter(object $message): void
{
// ...
}
}
Lifecycle actions
Transition hooks are registered with #[On*] attributes and
SceneAction values, for example
#[OnMessage(action: SceneAction::Enter)].
The enter() / leave() / exit() / back() / retake() methods below
are parity stubs for user code that wants to call them explicitly; framework
transitions dispatch attribute actions through SceneWizard.
SceneWizard
The $wizard property is typed as SceneWizard (Task 5.9). Subclasses
receive a fully initialised wizard instance from the framework.
Table of Contents
Properties
- $wizard : SceneWizard
- The wizard that manages scene transitions for this instance.
- $cachedSceneConfig : array<Scene>, SceneConfig>
- Per-class cache of reflection-built `SceneConfig` instances.
Methods
- __construct() : mixed
- Construct a scene instance.
- addToRouter() : void
- Wire this scene's handlers into an existing router.
- asHandler() : callable(object, mixed...): void
- Return a callable that enters this scene when invoked.
- asRouter() : Router
- Return a `Router` sub-tree that registers this scene's handlers.
- back() : mixed
- Parity stub for custom scene code.
- enter() : mixed
- Parity stub for custom scene code.
- exit() : mixed
- Parity stub for custom scene code.
- leave() : mixed
- Parity stub for custom scene code.
- retake() : mixed
- Parity stub for custom scene code.
- sceneConfig() : SceneConfig
- Return the `SceneConfig` for this scene class.
- sceneState() : null|string
- Return the FSM state string declared by the `#[SceneState]` attribute on this class (or a subclass), or `null` when no attribute is present.
- buildSceneConfig() : SceneConfig
- Build a `SceneConfig` for this class by reflecting on `#[SceneState]` (class) and `#[On*]` (method) attributes.
- prepareSceneMethodArguments() : array<int|string, mixed>
- Bind the event and dispatcher kwargs to a reflected scene method.
- sceneParameterIsPositionalEvent() : bool
- sceneParameterNameLooksLikeEvent() : bool
Properties
$wizard
The wizard that manages scene transitions for this instance.
public
SceneWizard
$wizard
$cachedSceneConfig
Per-class cache of reflection-built `SceneConfig` instances.
private
static array<Scene>, SceneConfig>
$cachedSceneConfig
= []
Keyed by static::class so each subclass gets its own entry.
Populated lazily by buildSceneConfig() on first access.
Methods
__construct()
Construct a scene instance.
public
__construct(SceneWizard $wizard) : mixed
Parameters
- $wizard : SceneWizard
-
Scene wizard that drives transitions.
addToRouter()
Wire this scene's handlers into an existing router.
public
static addToRouter(Router $router) : void
For each HandlerContainer in sceneConfig()->handlers:
- Create a
SceneHandlerWrapperaround the handler. - Register it with the matching observer (keyed by
$handler->name, which is the Telegram event-type string such as'message'). - Track which observer names were used.
After all handlers are registered, add a StateFilter as a global
observer filter on every used observer (except callback_query when
callbackQueryWithoutState is true).
Mirrors Scene.add_to_router() (aiogram/fsm/scene.py:379-405).
Parameters
- $router : Router
asHandler()
Return a callable that enters this scene when invoked.
public
static asHandler([bool $checkActive = true ], mixed ...$handlerKwargs) : callable(object, mixed...): void
The returned closure is suitable for registering as a handler on any
observer. When invoked it calls $scenes->enter(static::class, $checkActive)
where $scenes is the ScenesManager injected by SceneRegistry middleware.
Mirrors Scene.as_handler() (aiogram/fsm/scene.py:423-438).
$checkActive — top-level parameter, not a kwarg
$checkActive is declared as an explicit typed parameter rather than
flowing through ...$handlerKwargs. This avoids a PHP duplicate-named-arg
error that would crash production when a middleware-injected kwarg named
checkActive collides with the same-named key being forwarded positionally
to ScenesManager::enter.
// Correct — uses the dedicated parameter: MyScene::asHandler(checkActive: false)
checkActive in the merged kwargs bag — silently dropped
Any kwarg literally named checkActive that arrives via $handlerKwargs
or the middleware bag is removed from the merged array before the enter()
call. This prevents the duplicate-named-arg crash for callers that
inadvertently include a checkActive key in their own kwargs payload.
The safety property from Cycle 1 is preserved: any other duplicate key
collision still produces a PHP Error at the enter() call site.
Parameters
- $checkActive : bool = true
-
When
true(default) the currently active scene is exited before entering this one. Passfalseto skip that step (e.g. for chained transitions). - $handlerKwargs : mixed
-
Extra kwargs merged into the
enter()call.
Return values
callable(object, mixed...): voidasRouter()
Return a `Router` sub-tree that registers this scene's handlers.
public
static asRouter([string|null $name = null ]) : Router
Mirrors Scene.as_router() (aiogram/fsm/scene.py:407-421).
The router name defaults to:
"Scene '<FQCN>' for state '
Parameters
- $name : string|null = null
-
Optional router name override.
Return values
Routerback()
Parity stub for custom scene code.
public
back(mixed ...$kwargs) : mixed
Framework transitions dispatch SceneAction::Back attribute handlers via
SceneWizard; they do not call this method directly.
Mirrors Scene.back() (aiogram/fsm/scene.py:414-416).
Default: returns null.
Parameters
- $kwargs : mixed
enter()
Parity stub for custom scene code.
public
enter(mixed ...$kwargs) : mixed
Framework transitions dispatch SceneAction::Enter attribute handlers via
SceneWizard; they do not call this method directly.
Mirrors Scene.enter() (aiogram/fsm/scene.py:400-404) as an overridable
method user code may call explicitly.
Default: returns null. Subclasses may return mixed.
Parameters
- $kwargs : mixed
exit()
Parity stub for custom scene code.
public
exit(mixed ...$kwargs) : mixed
Framework transitions dispatch SceneAction::Exit attribute handlers via
SceneWizard; they do not call this method directly.
Mirrors Scene.exit() (aiogram/fsm/scene.py:410-412).
Default: returns null.
Parameters
- $kwargs : mixed
leave()
Parity stub for custom scene code.
public
leave(mixed ...$kwargs) : mixed
Framework transitions dispatch SceneAction::Leave attribute handlers via
SceneWizard; they do not call this method directly.
Mirrors Scene.leave() (aiogram/fsm/scene.py:406-408).
Default: returns null.
Parameters
- $kwargs : mixed
retake()
Parity stub for custom scene code.
public
retake(mixed ...$kwargs) : mixed
No direct upstream equivalent — added for the PHP port's "retake"
concept used in wizard-style multi-step scenes.
Default: returns null.
Parameters
- $kwargs : mixed
sceneConfig()
Return the `SceneConfig` for this scene class.
public
static sceneConfig() : SceneConfig
On first call the config is built via reflection (reading #[SceneState]
from the class and #[On*] attributes from public methods) and cached in
self::$cachedSceneConfig[static::class]. Subsequent calls return the
cached instance without re-reflecting.
Subclasses that override this method explicitly (e.g. test fixtures that
hand-build a SceneConfig) bypass the reflection path entirely — the
override is called instead.
Mirrors the __scene_config__ class attribute populated in
Scene.__init_subclass__ (aiogram/fsm/scene.py:316-325).
Return values
SceneConfigsceneState()
Return the FSM state string declared by the `#[SceneState]` attribute on this class (or a subclass), or `null` when no attribute is present.
public
static sceneState() : null|string
Resolution order:
- The
#[SceneState('explicit_state')]attribute value (non-null). - If the attribute is absent, or present with
$state = null, returnnull. UpstreamScene.__init_subclass__defaultsstatetoNonewhen thestate=kwarg is omitted; this port mirrors that behaviour. Users who want a named state must supply#[SceneState('mystate')].
Mirrors the state-name resolution in Scene.__init_subclass__
(aiogram/fsm/scene.py:318-322).
Return values
null|string —The resolved FSM state string, or null when no
explicit state has been declared.
buildSceneConfig()
Build a `SceneConfig` for this class by reflecting on `#[SceneState]` (class) and `#[On*]` (method) attributes.
private
static buildSceneConfig() : SceneConfig
Algorithm:
- Read
#[SceneState]from the class →$stateName. - For each public method, read all
#[On*]attributes:- Attribute with
$action === null→HandlerContainerentry in$handlers(ordinary event handler). - Attribute with
$action !== null→ entry in$actionskeyed by$action->name(lifecycle action handler).
- Attribute with
- Construct and return the
SceneConfig.
Mirrors Scene.__init_subclass__ (aiogram/fsm/scene.py:321-377).
Return values
SceneConfigprepareSceneMethodArguments()
Bind the event and dispatcher kwargs to a reflected scene method.
private
static prepareSceneMethodArguments(ReflectionMethod $method, object $event, array<int|string, mixed> $kwargs) : array<int|string, mixed>
Scene methods are user handlers, so they should receive the same kwarg filtering ergonomics as normal dispatcher handlers: strict signatures get only declared parameter names, while a variadic tail opts in to the full workflow-data bag.
Parameters
- $method : ReflectionMethod
- $event : object
- $kwargs : array<int|string, mixed>
Return values
array<int|string, mixed>sceneParameterIsPositionalEvent()
private
static sceneParameterIsPositionalEvent(ReflectionParameter $parameter, object $event) : bool
Parameters
- $parameter : ReflectionParameter
- $event : object
Return values
boolsceneParameterNameLooksLikeEvent()
private
static sceneParameterNameLooksLikeEvent(ReflectionParameter $parameter) : bool
Parameters
- $parameter : ReflectionParameter