Статьи

Console Wars — PHP CLI библиотеки

Я всегда был большим поклонником консольных команд, и я стараюсь максимально использовать интерфейс командной строки (CLI) в большинстве моих проектов PHP.

В этой статье я кратко сравню три библиотеки команд консоли PHP:

Image of terminal screen

Происхождение истории

Консоль Symfony является самой старой и самой популярной, используемой во многих проектах (и, очевидно, частью инфраструктуры Symfony). С десятками участников это стало первым выбором для многих разработчиков.

Hoa — это модульный, расширяемый и структурированный набор библиотек PHP, который включает консоль Hoa . Он призван стать мостом между промышленным и исследовательским миром, и это делает этот проект довольно интересным.

Консоль Webmozart — это новейший проект, который хочет быть проще, удобнее в тестировании и добавляет новые функциональные возможности поверх консоли Symfony.

Зависимости, размер и сложность

Консоль Symfony имеет только предполагаемые зависимости, в отличие от библиотеки консоли Hoa, которая зависит от некоторых библиотек проекта Hoa . Проект Webmozart также напрямую зависит от консоли Symfony.

Консоль Hoa имеет наименьшее количество LOC (логических строк кода) ~ 1397, затем консоль Symfony ~ 2226 и Webmozart ~ 3126 (без зависимостей).

Чтобы получить приблизительный показатель сложности этих проектов, ниже приведены некоторые данные их анализа PHPLOC *:


Описание Symfony Хоа Webmozart
Цикломатическая Сложность
Средняя сложность за LLOC 0,37 0,36 0,26
Средняя сложность на класс 14,73 25,14 8,84
Средняя сложность на метод 2,55 3,38 1,99
зависимости
Глобальный доступ 3 20 1
Доступ к атрибутам 807 217 1285
Вызовы методов 1103 324 1320

* Анализ выполняется только в главном исходном каталоге, за исключением тестовой папки, если она имеется.

Практический пример

Описание

Чтобы получить общее представление о функциях каждой библиотеки и увидеть код в действии, давайте напишем бизнес-функцию для описания примера использования:

Feature: I want to output a message to several people. The message should be passed via the `--message` option and should be optional (default="Hello"), the message should be followed by two or more names, the message should be coloured with `--color=` (default="white") and/or in uppercase with `--up` (default=lowercase). 

Последний вызов консоли должен выглядеть примерно так:
somemsg --message='Good Morning' Nicola Bruno --color=green --up
и вывод должен быть:

 GOOD MORNING NICOLA AND BRUNO 

Реализация

Во-первых, нам нужно определить Message PHP, используемое в каждой консольной реализации, для обработки примера.

Ниже приведен довольно простой код:

 class Message { /** * Construct the class and initializes the properties. * * @param $names * @param string $message * @param bool $uppercase */ public function __construct($names, $message="Hello", $uppercase=false) { $this->names = implode(' and ', $names); $this->message = $message; $this->uppercase = $uppercase; } /** * Generates the output. * * @return string */ public function getMessage() { $output = $this->message . ' ' . $this->names; if ($this->uppercase) { $output = strtoupper($output); } return $output; } } 

Консоль Symfony

Чтобы создать консольную команду в Symfony, необходимо:

  • Создайте класс команды
    — настроить аргументы и параметры
    — написать логику
  • Создать приложение

Создать команду

 use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class MessageCommand extends Command { /** * Configures the argument and options */ protected function configure() { $this ->setName('demo:msg') ->setDescription('Simple message delivery') ->addArgument('names', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'Who do you want to message?') ->addOption('message', null, InputOption::VALUE_REQUIRED, 'Set the message', 'Hello') ->addOption('up', null, InputOption::VALUE_NONE, 'Set the output in uppercase') ->addOption('color', null, InputOption::VALUE_REQUIRED, 'Which colors do you like?', 'white') ; } /** * Executes the logic and creates the output. * * @param InputInterface $input * @param OutputInterface $output */ protected function execute(InputInterface $input, OutputInterface $output) { $names = $input->getArgument('names'); $message = $input->getOption('message'); $uppercase = $input->getOption('up'); $color = $input->getOption('color'); $message = new Message($names, $message, $uppercase); $messageString = $message->getMessage(); $coloredMsg = '<fg='.$color.'>'.$messageString.'</fg='.$color.'>'; $output->writeln($coloredMsg); } } 

Метод configure используется для настройки аргументов и параметров команды.

Метод addArgument может получить следующие параметры:
addArgument($name, $mode, $description, $default)


тип имя описание
строка $ имя Имя аргумента
ИНТ $ режим Режим аргумента: InputArgument :: REQUIRED или InputArgument :: OPTIONAL
строка $ описание Текст описания
смешанный $ по умолчанию Значение по умолчанию (только для режима InputArgument :: OPTIONAL)

addOption может получить следующие параметры:
addArgument($name, $shortcut, $mode, $description, $default)


тип имя описание
строка $ имя Название опции
строка $ ярлык Ярлык (может быть нулевым)
ИНТ $ режим Режим параметра: одна из констант InputOption :: VALUE_ *
строка $ описание Текст описания
смешанный $ по умолчанию Значение по умолчанию (должно быть нулевым для InputOption :: VALUE_REQUIRED или InputOption :: VALUE_NONE)

Есть три варианта цвета для вывода:

  • Используйте предустановленный тег (es: $output->writeln('<info>foo</info>'); для зеленого вывода)
  • Определите стиль, используя класс OutputFormatterStyle
  • Установите цвет внутри имени тега es:
 // red text on a cyan background $output->writeln('<fg=red;bg=cyan>foo</fg=red;bg=cyan>'); 

Доступны следующие цвета переднего плана и фона: черный, красный, зеленый, желтый, синий, пурпурный, голубой и белый. Доступны следующие варианты: полужирный, подчеркивание, мигание, реверс и скрытие.

Больше информации в официальной документации Symfony .

Примечание : по умолчанию командная консоль Windows не поддерживает раскраску вывода. Вам понадобятся (и должны будут установить) инструменты Git или другая более сложная командная консоль.

Создать приложение

После настройки и выполнения мы почти закончили. Последний шаг — создание файла PHP для запуска команды.

 //file myconsole.php require __DIR__.'/vendor/autoload.php'; use MessageCommand; use Symfony\Component\Console\Application; $application = new Application(); $application->add(new MessageCommand()); $application->run(); 

Пример вызова консоли:

 php myconsole.php demo:msg Nicola Bruno --message='Good Morning' --color=blue --up 

Консоль Symfony также автоматически предоставляет помощнику вывода аргумент --help .

Хоа консоль

Консоль Hoa использует менее структурированный подход к настройке команды консоли.

Этот процесс состоит из следующих шагов:

  • Разобрать команду
  • Получить параметры и ввод
  • Выполнить логику

Разобрать команду

 /** * $argv contains an array of all the arguments passed to the script, * the first argument is always the name of the PHP file. * the Hoa Parser->parse method accept a string in input, so it's necessary to convert the $argv array in a string without the first argument as below. */ unset($argv[0]); $command = implode(' ', $argv); $parser = new Hoa\Console\Parser(); $parser->parse($command); //options definition //['longname', TYPE, 'shortname'] $options = new Hoa\Console\GetOption( [ ['up', Hoa\Console\GetOption::NO_ARGUMENT, 'u'], ['message', Hoa\Console\GetOption::REQUIRED_ARGUMENT, 'm'], ['color', Hoa\Console\GetOption::OPTIONAL_ARGUMENT, 'c'] ], $parser ); с /** * $argv contains an array of all the arguments passed to the script, * the first argument is always the name of the PHP file. * the Hoa Parser->parse method accept a string in input, so it's necessary to convert the $argv array in a string without the first argument as below. */ unset($argv[0]); $command = implode(' ', $argv); $parser = new Hoa\Console\Parser(); $parser->parse($command); //options definition //['longname', TYPE, 'shortname'] $options = new Hoa\Console\GetOption( [ ['up', Hoa\Console\GetOption::NO_ARGUMENT, 'u'], ['message', Hoa\Console\GetOption::REQUIRED_ARGUMENT, 'm'], ['color', Hoa\Console\GetOption::OPTIONAL_ARGUMENT, 'c'] ], $parser ); 

Получить варианты и входные данные

 //definition of default values $uppercase = false; $message = "Hello"; $color = "white"; $names = $parser->getInputs(); //The following while with the switch will assign the values to the variables. while (false !== $shortName = $options->getOption($value)) { switch ($shortName) { case 'u': $uppercase = true; break; case 'm': $message = $value; break; case 'c': $color = $value; break; } } 

Выполнить логику

 $message = new Message($names, $message, $uppercase); $messageString = $message->getMessage(); Hoa\Console\Cursor::colorize('fg('.$color.')'); echo $messageString; Hoa\Console\Cursor::colorize('fg(white)'); //reset the cursor to default white 

Для окрашивания вывода можно изменить цвет Cursor .

Консоль Hoa поддерживает широкий спектр цветов.
Цвет можно установить по имени (черный, красный, зеленый, желтый…), по номеру (от 0 до 256, представляющему цветовую палитру 264) или по шестнадцатеричному коду #rrggbb, пример:
Hoa\Console\Cursor::colorize('fg(yellow) bg(#932e2e) underlined');

Основное использование в этом примере не обеспечивает автоматический вывод вспомогательных данных и не ориентировано строго на ООП, но расширение Hoa\Console\Dispatcher\Kit (требует hoa/dispatcher ) может добавить больше гибкости (больше информации в официальной документации )

Команду можно вызвать с помощью:

 php message.php -u --message=Hello --color=green Nicola Bruno 

Одной из сильных сторон консоли Hoa является то, что она предоставляет дополнительные классы API для управления важными элементами, поддерживая различные профили терминала:

  • Cursor (переместить, очистить, показать, раскрасить,…)
  • Mouse (слушая действия мыши)
  • Window (setSize, прокрутка, сворачивание, …)
  • Линия терминала с Readline (история, автозаполнение и т. Д.)

Консоль Webmozart

Рабочий процесс создания команды консоли Webmozart состоит из:

  • настройка аргумента и параметров
  • писать логику
  • создание приложения

Консоль Webmozart следует подходу, аналогичному консоли Symfony, но с четким разделением между конфигурацией и логическим выполнением.

конфигурация

 use Webmozart\Console\Api\Args\Format\Argument; use Webmozart\Console\Api\Args\Format\Option; use Webmozart\Console\Config\DefaultApplicationConfig; /** * Configuration of arguments and options */ class MsgApplicationConfig extends DefaultApplicationConfig { protected function configure() { parent::configure(); $this ->setName('msg') ->setVersion('0.1') ->beginCommand('msg') ->setDescription('Show a nice message') ->setHandler(new MsgCommandHandler()) ->addArgument('names', Argument::MULTI_VALUED | Argument::REQUIRED, 'Who do you want to message?') ->addOption('message', null, Option::OPTIONAL_VALUE, 'Set the message', 'Hello') ->addOption('up', null, Option::NO_VALUE, 'Set the output in uppercase') ->addOption('color', null, Option::REQUIRED_VALUE, 'Which colors do you like?', 'white') ->end() ; } } 

логика

 use Webmozart\Console\Api\Args\Args; use Webmozart\Console\Api\IO\IO; /** * Handling the command logic */ class MsgCommandHandler { public function handle(Args $args, IO $io) { //gets the argument and option $names = $args->getArgument('names'); $message = $args->getOption('message'); $uppercase = $args->getOption('up'); $color = $args->getOption('color'); $message = new Message($names, $message, $uppercase); $messageString = $message->getMessage(); $coloredMsg = '<fg='.$color.'>'.$messageString.'</fg='.$color.'>'; $io->writeLine($coloredMsg); } } 

Сильное разделение конфигурации и логики обеспечивает большую гибкость для простого тестирования и для проекта, который будет расти с дополнительными командами.

Другие преимущества консоли Webmozart:

  • поддержка подкоманд:

     php mycommand.php msg send --arg1 --arg2 php mycommand.php msg receive --someoptions=somevalue 
  • поддержка документации man-страницы (например, с помощью «git help remote»)

  • адаптеры для консоли Symfony (для использования классов Symfony, таких как ProgressBar)

Создание приложения

Файл приложения для запуска команды похож на файл Symfony:

 require 'vendor/autoload.php'; use Webmozart\Console\ConsoleApplication; $cli = new ConsoleApplication(new MsgApplicationConfig()); $cli->run(); 

Консольный звонок:

 php myconsole.php msg --message='Good Morning' Nicola Bruno --color=blue --up 

Последние мысли

Каждая описанная выше консоль предоставляет различные функции для разных типов использования и пользовательских предпочтений.

  • Консоль Symfony хорошо протестирована, надежна, имеет хорошую документацию и функции для решения большинства обычных случаев использования.
  • Консоль Hoa более ориентирована на отрасль и идеально подходит для манипулирования терминальной средой (мышь, курсор, окно и т. Д.).
  • Консоль Webmozart является новой (скоро будет стабильная версия), но она очень полезна для работы с проектами, которые имеют тенденцию расти до больших размеров.

Вы регулярно используете какой-либо из них? Если да, то какой? Почему? Что бы вы сказали за и против каждого? У вас есть другие претенденты, чтобы предложить? Дайте нам знать!