Я всегда был большим фанатом консольных команд и я стараюсь предоставлять консольный командный инструмент (CLI) на столько, на сколько это возможно, в в большинстве моих PHP проектах.
В этой статье я кратко сравню три PHP консольные библиотеки:
- The Symfony console component (symfony/Console)
- The Hoa console (hoa/console)
- The Webmozart console (webmozart/console)
Истории создания
Консоль Symfony старейшая и самая популярная, используется во множестве проектов (и, очевидно, часть Symfony фреймворка). С множеством контрибьюторов это стало первым выбором для многих разработчиков.
Hoa это модульный, расширяемый и структурированный набор из PHP библиотек, которые включает Hoa консоль. Она стремится быть мостом между индустриальным и исследовательским миром и это делает этот проект достаточно интересным.
Консоль Webmozart это новейший проект, стремится быть легким, дружелюбным к тестам и добавить новый функционал поверх консоли Symfony.
Зависимости, Размер и Сложность
Консоль Symfony только предлагает зависимости, в отличии от бибилотеки Hoa консоль, которая зависит от некоторых библиотек проекта Hoa. Проект Webmozart так же прямо зависит от консоли Symfony.
Консоль Hoa имеет наименьшее число LOC (Logical Lines of Code (логические строки кода)) ~1397, далее следует Symfony консоль ~2226 и Webmozart ~3126 (без зависимостей)
Для получения примерного индикатора сложности этих проектов, ниже приведены некоторые данные из ихнего PHPLOC анализа*:
Description | Symfony | Hoa | Webmozart |
---|---|---|---|
Cyclomatic Complexity | |||
Average Complexity per LLOC | 0.37 | 0.36 | 0.26 |
Average Complexity per Class | 14.73 | 25.14 | 8.84 |
Average Complexity per Method | 2.55 | 3.38 | 1.99 |
Dependencies | |||
Global Accesses | 3 | 20 | 1 |
Attribute Accesses | 807 | 217 | 1285 |
Method Calls | 1103 | 324 | 1320 |
*Анализ выполнен только в главном каталоге исходников, исключая папку тестов, если присутствует.
Практический пример
Описание
Для обзора функционала каждой библиотеки и просмотра кода в действии, давайте реализуем бизнес требование, которое описывает следующий пример использования:
1 2 3 4 5 6 |
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
и вывод должен быть:
1 2 3 |
GOOD MORNING NICOLA AND BRUNO |
Реализация
Для начала мы должны определить PHP Message, используемый в каждой реализации консоли для реализации примера.
Ниже некоторый достаточно простой код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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 необходимо:
- Создать класс команды
– Сконфигурировать аргументы и опции
– Написать логику - Создать приложение
Создание команды
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
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 { /** * Сконфигурировать аргументы и опции */ 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') ; } /** * Выполнить логику и создать вывод * * @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)
type | name | description |
---|---|---|
string | $name | Имя аргумента |
int | $mode | Режим аргумента: InputArgument::REQUIRED или InputArgument::OPTIONAL |
string | $description | Текст описания |
mixed | $default | Значение по умолчанию (только для режима InputArgument::OPTIONAL) |
addOption может принимать следующие параметры: addArgument($name, $shortcut, $mode, $description, $default)
type | name | description |
---|---|---|
string | $name | Имя опции |
string | $shortcut | Сокращение (может быть null) |
int | $mode | Режим опции: Одна из InputOption::VALUE_* констант |
string | $description | Текст описания |
mixed | $default | Значение по умолчанию (должно быть null для InputOption::VALUE_REQUIRED или InputOption::VALUE_NONE) |
Доступны три способа для цветного вывода:
- Использовать предустановленный тег (как: $output->writeln('<info>foo</info>'); для вывода зеленым)
- Определить стиль используя класс OutputFormatterStyle
- Установить цвет внутри имени тега, как:
1 2 3 4 |
// красный текст на бирюзовом фоне $output->writeln('<fg=red;bg=cyan>foo</fg=red;bg=cyan>'); |
Доступные цвета переднего плана и фона: черный, красный, зеленый, желтый, синий, пурпурный и бирюзовый. Доступные опции: жирный, подчеркнутый, мигающий, обратный и скрытый.
Больше информации в оффициальной документации Symfony.
Заметка: по умолчанию командная консоль Windows не поддерживает цветной вывод. Вам нужны (и необходимо установить) Git tools и другие более продвинутые командные консоли.
Создание приложения
После конфигурирования и исполнения мы почти закончили. Последний шаг это создание PHP файла для запуска команды.
1 2 3 4 5 6 7 8 9 10 11 12 |
//file myconsole.php require __DIR__.'/vendor/autoload.php'; use MessageCommand; use Symfony\Component\Console\Application; $application = new Application(); $application->add(new MessageCommand()); $application->run(); |
Пример консольного вызова:
1 2 3 |
php myconsole.php demo:msg Nicola Bruno --message='Good Morning' --color=blue --up |
Консоль Symfony так же автоматически предоставляет вывод помощи с –help аргументом.
Консоль Hoa
Консоль Hoa следует мене структурированному подходу для конфигурации консольной команды.
Процесс состоит из следующих шагов:
- Распознавание команды
- Получение опций и ввода
- Выполнение логики
Распознавание команды
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/** * $argv содержит массив всех аргументов переданных в скрипт, * первый аргумент эт овсегда имя PHP файла. * Hoa метод Parser->parse принимает строку на ввод, поэтому необходимо конвертировать массив $argv в строку без первого аргумента, как ниже. */ unset($argv[0]); $command = implode(' ', $argv); $parser = new Hoa\Console\Parser(); $parser->parse($command); //определение опций //['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 ); |
Получение опций и ввода
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//определение значений по умолчанию $uppercase = false; $message = "Hello"; $color = "white"; $names = $parser->getInputs(); //Следующее через переключатель будет назначать значение к переменной. while (false !== $shortName = $options->getOption($value)) { switch ($shortName) { case 'u': $uppercase = true; break; case 'm': $message = $value; break; case 'c': $color = $value; break; } } |
Выполнение логики
1 2 3 4 5 6 7 8 |
$message = new Message($names, $message, $uppercase); $messageString = $message->getMessage(); Hoa\Console\Cursor::colorize('fg('.$color.')'); echo $messageString; Hoa\Console\Cursor::colorize('fg(white)'); //сбросить курсор к белому по умолчанию |
Для раскраски вывода возможно сменить цвет у Cursor.
Консоль Hoa поддерживает широкий набор цветов.
Цвет может быть установлен по имени (черный, красный, зеленый, желтый…), по номеру (от 0 до 256 представляет 264 цветовую палитру) или через шестнадцатиричный код #rrggbb, например:
1 2 3 |
Hoa\Console\Cursor::colorize('fg(yellow) bg(#932e2e) underlined'); |
Базовое использование в примере не предоставляет автоматического вывода помощи и не строго ООП ориентировано, но наследование от Hoa\Console\Dispatcher\Kit (требует hoa/dispatcher) может добавить больше гибкости (больше информации в официальной документации).
Команда может быть вызвана так:
1 2 3 |
php message.php -u --message=Hello --color=green Nicola Bruno |
Одна из сильных сторон консоли Hoa в том, что она предоставляет дополнительные API классы для манипуляции важными элементами, поддерживая разные профили терминала:
- The Cursor (движение, очистка, показ, раскраска, …)
- The Mouse (прослушиваение действий мышью)
- The Window (setSize, скроллинг, минимизация, …)
- Терминальная линия Readline (история, автозавершение, и др.)
Консоль Webmozart
Процесс создания команды в консоли Webmozart состоит из:
- конфигурирование аргументов и опций
- написнаие логики
- создание приложения
Консоль Webmozart следует подходу похожему на консоль Symfony, но с ясным разделением между конфигурацией и выполнением логики.
Конфигурация
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
use Webmozart\Console\Api\Args\Format\Argument; use Webmozart\Console\Api\Args\Format\Option; use Webmozart\Console\Config\DefaultApplicationConfig; /** * Конфигурация аргументов и опций */ 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() ; } } |
Логика
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
use Webmozart\Console\Api\Args\Args; use Webmozart\Console\Api\IO\IO; /** * Обработка логики команды */ class MsgCommandHandler { public function handle(Args $args, IO $io) { //получение аргументов и опций $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 это:
- поддержка подкоманд:
1234php mycommand.php msg send --arg1 --arg2php mycommand.php msg receive --someoptions=somevalue - поддержка страницы руководства (как git help remote)
- адаптеры для консоли Symfony (чтобы использовать классы Symfony как ProgressBar)
Создание приложения
Файл приложения для запуска команды схож файлом Symfony:
1 2 3 4 5 6 7 |
require 'vendor/autoload.php'; use Webmozart\Console\ConsoleApplication; $cli = new ConsoleApplication(new MsgApplicationConfig()); $cli->run(); |
Консольный вызов:
1 2 3 |
php myconsole.php msg --message='Good Morning' Nicola Bruno --color=blue --up |
Заключительные мысли
Каждая упомянутая выше консоль предоставляет различную функциональность для различных типов применения и пользовательских предпочтений.
- консоль Symfony хорошо протестирована, надежна, с хорошей документацией и функциями для решения большинства обычных способов использования.
- консоль Hoa более индустриально ориентирована, идеальна для манипулирования терминальным окружением (мышь, курсор, окно и так далее).
- консоль Webmozart нова (скоро будет стабильный релиз), но очень удобна для работы с проектами, которые имеют склонность расти до больших размеров.
Вы используете какие-то из них регулярно? Если да, то какие? Что вы скажете о плюсах и минусах каждой из них? Вы можете предложить других претендентов? Дайте нам знать!
Оригинал на английском:
http://www.sitepoint.com/console-wars-php-cli-libraries/
Это мой перевод. Если вы заметили ошибки или считаете, что какие-то части можно перевести лучше – пишите в комментарии.