symfony/console

github地址:GitHub - symfony/console: Eases the creation of beautiful and testable command line interfaces

文档地址:The Console Component (Symfony 5.4 Docs)

默认命令list,可以用register注册一个command命令,之后可以设置其他内容,或者设置命令类再加到框架中。

#Symfony\Component\Console\Application
public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
    {
        $this->name = $name;
        $this->version = $version;
        $this->terminal = new Terminal();
        $this->defaultCommand = 'list';
        if (\defined('SIGINT') && SignalRegistry::isSupported()) {
            $this->signalRegistry = new SignalRegistry();
            $this->signalsToDispatchEvent = [\SIGINT, \SIGTERM, \SIGUSR1, \SIGUSR2];
        }
    }
public function register(string $name)
    {
        return $this->add(new Command($name));
    }
public function add(Command $command)
    {
    ……
     $this->commands[$command->getName()] = $command;
    ……
    }


#Symfony\Component\Console\Command\Command
//设置执行代码
public function setCode(callable $code)
    {
        if ($code instanceof \Closure) {
            $r = new \ReflectionFunction($code);
            if (null === $r->getClosureThis()) {
                set_error_handler(static function () {});
                try {
                    if ($c = \Closure::bind($code, $this)) {
                        $code = $c;
                    }
                } finally {
                    restore_error_handler();
                }
            }
        }

        $this->code = $code;

        return $this;
    }
//设置命令名
public function setName(string $name)
    {
        $this->validateName($name);

        $this->name = $name;

        return $this;
    }
//设置别名
 public function setAliases(iterable $aliases)
    {
        $list = [];

        foreach ($aliases as $alias) {
            $this->validateName($alias);
            $list[] = $alias;
        }

        $this->aliases = \is_array($aliases) ? $aliases : $list;

        return $this;
    }
//设置帮助内容
public function setHelp(string $help)
    {
        $this->help = $help;

        return $this;
    }
//设置是否隐藏
public function setHidden(bool $hidden /* = true */)
    {
        $this->hidden = $hidden;

        return $this;
    }
//设置描述
public function setDescription(string $description)
    {
        $this->description = $description;

        return $this;
    }
#运行文件
require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/Test1Command.php';

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

$application = new Application();
$application
    ->register('test')
    ->addArgument('username', InputArgument::REQUIRED, '用户名')
    ->addOption('pwd', "P", InputArgument::REQUIRED, '密码')
    ->setDescription("test command")
    ->setCode(function (InputInterface $input, OutputInterface $output) {
        return Command::SUCCESS;
    });
$test1command = new Test1Command();
$application->add($test1command);
$application->run();

#Test1Command
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class Test1Command extends Command
{
    protected function configure()
    {
        $this->setName("test1");
        $this->setHelp('This command allows you to create a user...');
        $this->addArgument('test', InputArgument::REQUIRED, 'test');
        $this->setDescription("test1 command");

    }
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        var_dump($input->getArguments());

        //$listcommand = $this->getApplication()->get('list');
        //$listcommand->run($input, $output);
        $input = new ArrayInput(['command' => 'list']);
        $listcommand = $this->getApplication()->get('list');
        $listcommand->run($input, $output);
        $output->writeln([
            'Test1 Command',
            '============',
            '',
        ]);
        return Command::SUCCESS;
    }
}

InputInterface实体类为Symfony\Component\Console\Input\ArgvInput,该类继承Symfony\Component\Console\Input\Input,会校验参数和用于获取参数。

#Symfony\Component\Console\Application
public function run(InputInterface $input = null, OutputInterface $output = null)
    {
        if (\function_exists('putenv')) {
            @putenv('LINES=' . $this->terminal->getHeight());
            @putenv('COLUMNS=' . $this->terminal->getWidth());
        }

        if (null === $input) {
            //默认input
            $input = new ArgvInput();
        }

        if (null === $output) {
            //默认输出
            $output = new ConsoleOutput();
        }
        ……
         $exitCode = $this->doRun($input, $output);
        ……
    }
public function doRun(InputInterface $input, OutputInterface $output)
    {
        $input->bind($this->getDefinition());
        ……
        $name = $this->getCommandName($input);
        ……
        if (!$name) {
            $name = $this->defaultCommand;
            $definition = $this->getDefinition();
            $definition->setArguments(array_merge(
                $definition->getArguments(),
                [
                    'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),
                ]
            ));
        }
       ……
     try {
            $this->runningCommand = null;
            // the command name MUST be the first element of the input
            $command = $this->find($name);
        } catch (\Throwable $e) {
            ……
            $alternatives = $e->getAlternatives();
            ……
            $alternative = $alternatives[0];
            ……
            $command = $this->find($alternative);
        }
        if ($command instanceof LazyCommand) {
            $command = $command->getCommand();
        }

        $this->runningCommand = $command;
        $exitCode = $this->doRunCommand($command, $input, $output);
        $this->runningCommand = null;

        return $exitCode;
    }

#Symfony\Component\Console\Exception\CommandNotFoundException
class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface
{
    private $alternatives;

    /**
     * @param string          $message      Exception message to throw
     * @param string[]        $alternatives List of similar defined names
     * @param int             $code         Exception code
     * @param \Throwable|null $previous     Previous exception used for the exception chaining
     */
    public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null)
    {
        parent::__construct($message, $code, $previous);

        $this->alternatives = $alternatives;
    }

    /**
     * @return string[]
     */
    public function getAlternatives()
    {
        return $this->alternatives;
    }
}

#Symfony\Component\Console\Input\Input
public function __construct(InputDefinition $definition = null)
    {
        if (null === $definition) {
            $this->definition = new InputDefinition();
        } else {
            //校验选项
            $this->bind($definition);
            //校验参数
            $this->validate();
        }
    }
//校验参数
public function validate()
    {
        $definition = $this->definition;
        $givenArguments = $this->arguments;

        $missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) {
            return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired();
        });

        if (\count($missingArguments) > 0) {
            throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments)));
        }
    }
//获取所有参数
public function getArguments()
    {
        return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
    }
//根据变量名获取参数
public function getArgument(string $name)
    {
        if (!$this->definition->hasArgument($name)) {
            throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
        }

        return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault();
    }
//设置参数值
 public function setArgument(string $name, $value)
    {
        if (!$this->definition->hasArgument($name)) {
            throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
        }

        $this->arguments[$name] = $value;
    }
//判断是否有参数
public function hasArgument(string $name)
    {
        return $this->definition->hasArgument($name);
    }
//获取全部选项
 public function getOptions()
    {
        return array_merge($this->definition->getOptionDefaults(), $this->options);
    }
//根据名称获取选项值
public function getOption(string $name)
    {
        if ($this->definition->hasNegation($name)) {
            if (null === $value = $this->getOption($this->definition->negationToName($name))) {
                return $value;
            }

            return !$value;
        }

        if (!$this->definition->hasOption($name)) {
            throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
        }

        return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
    }
//设置选项值
public function setOption(string $name, $value)
    {
        if ($this->definition->hasNegation($name)) {
            $this->options[$this->definition->negationToName($name)] = !$value;

            return;
        } elseif (!$this->definition->hasOption($name)) {
            throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
        }

        $this->options[$name] = $value;
    }
//判断是否有选项值
public function hasOption(string $name)
    {
        return $this->definition->hasOption($name) || $this->definition->hasNegation($name);
    }


#Symfony\Component\Console\Input\ArgvInput
protected function parse()
    {
        $parseOptions = true;
        $this->parsed = $this->tokens;
        while (null !== $token = array_shift($this->parsed)) {
            $parseOptions = $this->parseToken($token, $parseOptions);
        }
    }
protected function parseToken(string $token, bool $parseOptions): bool
    {
        if ($parseOptions && '' == $token) {
            $this->parseArgument($token);
        } elseif ($parseOptions && '--' == $token) {
            return false;
        } elseif ($parseOptions && str_starts_with($token, '--')) {
            $this->parseLongOption($token);
        } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
            $this->parseShortOption($token);
        } else {
            $this->parseArgument($token);
        }

        return $parseOptions;
    }
private function parseShortOption(string $token)
    {
        $name = substr($token, 1);

        if (\strlen($name) > 1) {
            if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
                // an option with a value (with no space)
                $this->addShortOption($name[0], substr($name, 1));
            } else {
                $this->parseShortOptionSet($name);
            }
        } else {
            $this->addShortOption($name, null);
        }
    }
 private function addShortOption(string $shortcut, $value)
    {
        if (!$this->definition->hasShortcut($shortcut)) {
            throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
        }

        $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
    }

运行

 php test.php test 123
php test.php test --help

Description:
  test command

Usage:
  test [options] [--] 

Arguments:
  username              用户名

Options:
  -P, --pwd             密码
  -h, --help            Display help for the given command. When no command is given display help for the list command
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi|--no-ansi  Force (or disable --no-ansi) ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Help:
  123
php test.php test1 --help

Description:
  test1 command

Usage:
  test1 

Arguments:
  test                  test

Options:
  -h, --help            Display help for the given command. When no command is given display help for the list command
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi|--no-ansi  Force (or disable --no-ansi) ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Help:
  This command allows you to create a user...
php test.php test1 111

array(2) {
  'command' =>
  string(5) "test1"
  'test' =>
  string(3) "111"
}
Console Tool

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display help for the given command. When no command is given display help for the list command
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi|--no-ansi  Force (or disable --no-ansi) ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  completion  Dump the shell completion script
  help        Display help for a command
  list        List commands
  test        test command
  test1       test1 command
Test1 Command
============

你可能感兴趣的:(php,symfony,php)