phpbotgram

Command extends Filter
in package

FinalYes

Slash-command matcher. Port of `aiogram.filters.command.Command` (`aiogram/filters/command.py:25-198`). Accepts a message and matches its `text` (or fallback `caption`) against one or more registered command patterns. On match, returns `['command' => CommandObject]` so the parsed pieces flow into the handler as a `$command` kwarg.

Constructor shape

Upstream's signature is Command(*values, *, prefix, ignore_case, ignore_mention, magic). PHP forbids parameters after a variadic, so the port collapses the variadic into a string|list<string> first argument and exposes Command::of(...$cmds) as a variadic-friendly factory.

new Command(['start', 'help']) // array form new Command('start') // single string new Command('start', ignoreCase: true) // single + flags Command::of('start', 'help') // variadic shorthand new Command(['start'], prefix: '/!') // string form: upstream parity ('/!' -> ['/', '!']) new Command(['start'], prefix: ['/', '!']) // list form: same result new Command(['start'], prefix: ['!cmd']) // list-only: multi-char prefix (PHP extension)

Match algorithm (mirrors upstream parse_command)

  1. Reject early when the event is not a Message or when both text and caption are absent / empty.
  2. Find the longest prefix from $prefix that the text starts with; bail if none match.
  3. Split the post-prefix tail on the first whitespace run — left side is the candidate command, right side is the args (or null).
  4. If the candidate contains @, split on the FIRST @ only; the right side becomes the mention (matching upstream's partition('@')). Mirrors upstream issue aiogram/aiogram#1013: a missing mention surfaces as null, never as ''.
  5. If ignoreMention is false AND a bot is supplied AND a mention is present, compare against bot.me().username case-insensitively. Mismatch → reject. Missing bot (e.g. unit tests that don't wire one) → skip the mention check (parity with upstream where the dispatcher always supplies one). Failures inside me() (network, mocked fixtures without canned response) are absorbed so tests don't have to seed getMe responses for every command-filter scenario.
  6. Walk the registered commands in declaration order, comparing with strcasecmp or === depending on $ignoreCase. The first match builds the CommandObject and short-circuits.

Phase 4.7 scope

Strings only — regex / BotCommand / magic-filter post-validation / deep-link handling all land in later tasks. The class is structured so those surfaces can be added without churning the constructor or call shape.

Table of Contents

Properties

$commands  : array<int, string>
$ignoreCase  : bool
$ignoreMention  : bool
$prefix  : array<int, string>

Methods

__construct()  : mixed
__invoke()  : array<string, mixed>|false
Filter entry point. Returns either `false` (reject) or `['command' => CommandObject]` (accept with a single kwarg). See class docblock for the per-step algorithm.
all()  : AndFilter
Compose an AND across filters: every child must accept, kwargs cascade. PHP equivalent of Python's `f1 & f2`.
any()  : OrFilter
Compose an OR across filters: the first accepting child wins, no cascade. PHP equivalent of Python's `f1 | f2`.
invertOf()  : InvertFilter
Invert a filter's accept/reject decision. Named `invertOf` rather than `not` because PHP forbids a static and an instance method sharing one name in a single class (the instance-side `$f->not()` convenience may land in a later task).
of()  : self
Variadic-friendly factory mirroring upstream's `Command('start', 'help')` call shape. Equivalent to `new Command([$cmd1, $cmd2, ...])`.
commandMatches()  : bool
Compare a parsed command name against a registered pattern. Uses `strcasecmp` when `$ignoreCase` is set (functionally equivalent to upstream's casefolding for ASCII command strings, which is what the upstream parametrize block exercises). Strict `===` otherwise.
parseCommand()  : CommandObject|null
Parse `$text` into a `CommandObject` if it matches one of `$this->commands`.

Properties

$commands read-only

public array<int, string> $commands

Registered command patterns.

$ignoreCase read-only

public bool $ignoreCase = false

$ignoreMention read-only

public bool $ignoreMention = false

$prefix read-only

public array<int, string> $prefix

Acceptable command prefixes (default ['/']).

Methods

__construct()

public __construct(array<int, string>|string $commands[, array<int, string>|string $prefix = ['/'] ][, bool $ignoreCase = false ][, bool $ignoreMention = false ]) : mixed
Parameters
$commands : array<int, string>|string

Either a single command string or a list. Throws on empty list.

$prefix : array<int, string>|string = ['/']

Acceptable prefixes (default ['/']). Accepts either a list<string> of prefix strings (PHP-side extension; allows multi-character prefixes like ['!cmd']) or a plain string whose individual characters are each treated as a prefix — matching upstream's Command(prefix='/!') syntax where '/!' means "either / or !". First match wins during parsing.

$ignoreCase : bool = false
$ignoreMention : bool = false

__invoke()

Filter entry point. Returns either `false` (reject) or `['command' => CommandObject]` (accept with a single kwarg). See class docblock for the per-step algorithm.

public __invoke(object $event, mixed ...$kwargs) : array<string, mixed>|false
Parameters
$event : object
$kwargs : mixed
Return values
array<string, mixed>|false

all()

Compose an AND across filters: every child must accept, kwargs cascade. PHP equivalent of Python's `f1 & f2`.

public static all(Filter ...$filters) : AndFilter
Parameters
$filters : Filter
Return values
AndFilter

any()

Compose an OR across filters: the first accepting child wins, no cascade. PHP equivalent of Python's `f1 | f2`.

public static any(Filter ...$filters) : OrFilter
Parameters
$filters : Filter
Return values
OrFilter

invertOf()

Invert a filter's accept/reject decision. Named `invertOf` rather than `not` because PHP forbids a static and an instance method sharing one name in a single class (the instance-side `$f->not()` convenience may land in a later task).

public static invertOf(Filter $filter) : InvertFilter
Parameters
$filter : Filter
Return values
InvertFilter

of()

Variadic-friendly factory mirroring upstream's `Command('start', 'help')` call shape. Equivalent to `new Command([$cmd1, $cmd2, ...])`.

public static of(string ...$commands) : self
Parameters
$commands : string
Return values
self

commandMatches()

Compare a parsed command name against a registered pattern. Uses `strcasecmp` when `$ignoreCase` is set (functionally equivalent to upstream's casefolding for ASCII command strings, which is what the upstream parametrize block exercises). Strict `===` otherwise.

private commandMatches(string $candidate, string $registered) : bool
Parameters
$candidate : string
$registered : string
Return values
bool

parseCommand()

Parse `$text` into a `CommandObject` if it matches one of `$this->commands`.

private parseCommand(string $text, Bot|null $bot) : CommandObject|null

Returns null on any mismatch (unknown prefix, wrong command name, mention mismatch).

Kept private — external callers should go through __invoke. The upstream method is public, but it is also async and tightly coupled to the filter's own validation methods (validate_prefix, validate_mention, validate_command). Inlining those into one routine here matches the PHP idiom and removes a layer of indirection.

Parameters
$text : string
$bot : Bot|null
Return values
CommandObject|null
On this page

Search results