📦consolidation / annotated-command
← 返回首页
Create Symfony Console commands from annotated command class methods.
⚖️ NOASSERTION📅 创建于 2016-03-23🔄 更新于 2026-03-29

📄 仓库 README

在 GitHub 查看 ↗
来自 GitHub 仓库自述文件 · 版权归原作者所有

Consolidation\AnnotatedCommand

Initialize Symfony Console commands from annotated/attributed command class methods.

CI scrutinizer codecov license

Component Status

Currently in use in Robo (1.x+), Drush (9.x+) and Terminus (1.x+).

Motivation

Symfony Console provides a set of classes that are widely used to implement command line tools. Increasingly, it is becoming popular to use annotations to describe the characteristics of the command (e.g. its arguments, options and so on) implemented by the annotated method.

Extant commandline tools that utilize this technique include:

This library provides routines to produce the Symfony\Component\Console\Command\Command from all public methods defined in the provided class.

Note If you are looking for a very fast way to write a Symfony Console-base command-line tool, you should consider using Robo, which is built on top of this library, and adds additional conveniences to get you going quickly. Use g1a/starter to quickly scaffold a new commandline tool. See Using Robo as a Framework. It is possible to use this project without Robo if desired, of course.

Library Usage

This is a library intended to be used in some other project. Require from your composer.json file:

    "require": {
        "consolidation/annotated-command": "^4"
    },

Example Annotated Command Class

The public methods of the command class define its commands, and the parameters of each method define its arguments and options. If a parameter has a corresponding "@option" annotation in the docblock, then it is an option; otherwise, it is an argument.

class MyCommandClass
{
    /**
     * This is the my:echo command
     *
     * This command will concatenate two parameters. If the --flip flag
     * is provided, then the result is the concatenation of two and one.
     *
     * @command my:echo
     * @param string $one The first parameter.
     * @param string $two The other parameter.
     * @param bool $flip The "flip" option
     * @option flip Whether or not the second parameter should come first in the result.
     * @aliases c
     * @usage bet alpha --flip
     *   Concatenate "alpha" and "bet".
     */
    public function myEcho($one, $two, $flip = false)
    {
        if ($flip) {
            return "{$two}{$one}";
        }
        return "{$one}{$two}";
    }
}

or via PHP 8 attributes.

    #[CLI\Name(name: 'my:echo', aliases: ['c'])]
    #[CLI\Help(description: 'This is the my:echo command', synopsis: "This command will concatenate two parameters. If the --flip flag\nis provided, then the result is the concatenation of two and one.",)]
    #[CLI\Param(name: 'one', description: 'The first parameter')]
    #[CLI\Param(name: 'two', description: 'The other parameter')]
    #[CLI\Option(name: 'flip', description: 'Whether or not the second parameter should come first in the result.')]
    #[CLI\Usage(name: 'bet alpha --flip', description: 'Concatenate "alpha" and "bet".')]
    public function myEcho($one, $two = '', $flip = false)
    {
        if ($options['flip']) {
            return "{$two}{$one}";
        }
        return "{$one}{$two}";
    }

Legacy Annotated Command Methods

The legacy method for declaring commands is still supported. When using the legacy method, the command options, if any, are declared as the last parameter of the methods. The options will be passed in as an associative array; the default options of the last parameter should list the options recognized by the command. The rest of the parameters are arguments. Parameters with a default value are optional; those without a default value are required.

class MyCommandClass
{
    /**
     * This is the my:echo command
     *
     * This command will concatenate two parameters. If the --flip flag
     * is provided, then the result is the concatenation of two and one.
     *
     * @command my:echo
     * @param integer $one The first parameter.
     * @param integer $two The other parameter.
     * @param array $options An option that takes multiple values.
     * @option flip Whether or not the second parameter should come first in the result.
     * @aliases c
     * @usage bet alpha --flip
     *   Concatenate "alpha" and "bet".
     */
    public function myEcho($one, $two, $options = ['flip' => false])
    {
        if ($options['flip']) {
            return "{$two}{$one}";
        }
        return "{$one}{$two}";
    }
}

Option Default Values

The $options array must be an associative array whose key is the name of the option, and whose value is one of:

  • The boolean value false, which indicates that the option takes no value.
  • A string containing the default value for options that may be provided a value, but are not required to.
  • The special value InputOption::VALUE_REQUIRED, which indicates that the user must provide a value for the option whenever it is used.
  • The special value InputOption::VALUE_OPTIONAL, which produces the following behavior:
  • If the option is given a value (e.g. --foo=bar), then the value will be a string.
  • If the option exists on the commandline, but has no value (e.g. --foo), then the value will be true.
  • If the option does not exist on the commandline at all, then the value will be null.
  • If the user explicitly sets --foo=0, then the value will be converted to false.
  • LIMITATION: If any Input object other than ArgvInput (or a subclass thereof) is used, then the value will be null for both the no-value case (--foo) and the no-option case. When using a StringInput, use --foo=1 instead of --foo to avoid this problem.
  • The special value true produces the following behavior:
  • If the option is given a value (e.g. --foo=bar), then the value will be a string.
  • If the option exists on the commandline, but has no value (e.g. --foo), then the value will be true.
  • If the option does not exist on the commandline at all, then the value will also be true.
  • If the user explicitly sets --foo=0, then the value will be converted to false.
  • If the user adds --no-foo on the commandline, then the value of foo will be false.
  • An empty array, which indicates that the option may appear multiple times on the command line.

No other values should be used for the default value. For example, $options = ['a' => 1] is incorrect; instead, use $options = ['a' => '1'].

Default values for options may also be provided via the @default annotation. See hook alter, below.

Hooks

Commandfiles may provide hooks in addition to commands. A commandfile method that contains a @hook annotation is registered as a hook instead of a command. The format of the hook annotation is:

@hook type target

The hook type determines when during the command lifecycle this hook will be called. The available hook types are described in detail below.

The hook target specifies which command or commands the hook will be attached to. There are several different ways to specify the hook target.

  • The command's primary name (e.g. my:command) or the command's method name (e.g. myCommand) will attach the hook to only that command.
  • An annotation (e.g. @foo) will attach the hook to any command that is annotated with the given label.
  • If the target is specified as *, then the hook will be attached to all commands.
  • If the target is omitted, then the hook will be attached to every command defined in the same class as the hook implementation.

There are ten types of hooks in the command processing request flow:

  • Command Event (Symfony)
  • @pre-command-event
  • @command-event
  • @post-command-event
  • Option
  • @pre-option
  • @option
  • @post-option
  • Initialize (Symfony)
  • @pre-init
  • @init
  • @post-init
  • Interact (Symfony)
  • @pre-interact
  • @interact
  • @post-interact
  • Validate
  • @pre-validate
  • @validate
  • @post-validate
  • Command
  • @pre-command
  • @command
  • @post-command
  • Process
  • @pre-process
  • @process
  • @post-process
  • Alter
  • @pre-alter
  • @alter
  • @post-alter
  • Status
  • @status
  • Extract
  • @extract

In addition to these, there are two more hooks available:

The "pre" and "post" varieties of these hooks, where available, give more flexibility vis-a-vis hook ordering (and for consistency). Within one type of hook, the running order is undefined and not guaranteed. Note that many validate, process and alter hooks may run, but the first status or extract hook that successfully returns a result will halt processing of further hooks of the same type.

Each hook has an interface that defines its calling conventions; however, any callable may be used when registering a hook, which is convenient if versions of PHP prior to 7.0 (with no anonymous classes) need to be supported.

Command Event Hook

The command-event hook is called via the Symfony Console command event notification callback mechanism. This happens prior to event dispatching and command / option validation. Note that Symfony does not allow the $input object to be altered in this hook; any change made here will be reset, as Symfony re-parses the object. Changes to arguments and options should be done in the initialize hook (non-interactive alterations) or the interact hook (which is naturally for interactive alterations).

Option Event Hook

The option event hook (OptionHookInterface) is called for a specific command,

📈 近 7 天 Star 趋势

每日新增 Star(柱)与累计 Star(线)· 数据来自 GitHub

🏆 排名变化趋势

在各榜单中的排名历史(数字越小越靠前)

📋 历史上榜记录

每次快照的详细数据
日期 榜单 排名 周期新增 总 STAR