cloud-castle/command

Быстрый раннер консольных команд для PHP 8.1+ без зависимостей: реестр с псевдонимами и ленивыми фабриками, строковые сигнатуры, команды из замыканий, подсказки при опечатке, хуки жизненного цикла, автодополнение, встроенные list/help, буферизованный раздельный вывод.

Maintainers

Package info

gitverse.ru/cloud-castle/command

Homepage

Issues

Documentation

pkg:composer/cloud-castle/command

Transparency log

Statistics

Installs: 40

Dependents: 1

Suggesters: 0

v1.4.0 2026-07-31 08:07 UTC

README

🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano

CloudCastle Command

CloudCastle Command

Packagist Version PHP Version License Total Downloads Monthly Downloads Dependents Suggesters

Repository Issues Wiki Release CI

PHPStan Psalm PHPMD PHPCS Coverage Infection MSI OpenSSF Scorecard

Быстрый раннер консольных команд: реестр по имени с псевдонимами и ленивыми фабриками, определения входа с проверкой и значениями по умолчанию, строковые сигнатуры, команды из замыканий, подсказки при опечатке, хуки жизненного цикла, встроенные list/help/completion, буферизованный раздельный вывод и красивое оформление из коробки через cloud-castle/cli. Без привязки к фреймворку.

Установка

composer require cloud-castle/command

Требуется PHP 8.1+. Единственная зависимость — cloud-castle/cli (оформление вывода: ANSI-стили, таблицы, рамки) той же экосистемы.

Быстрый старт

<?php

use CloudCastle\Command\Application;
use CloudCastle\Command\Input;
use CloudCastle\Command\Output;

$app = new Application();

// Команда из замыкания — без отдельного класса.
$app->command('greet', static function (Input $input, Output $output): int {
    $output->writeln('Привет, ' . ($input->getArgument(0) ?? 'мир'));

    return 0;
}, 'Приветствие');

$output = new Output();
$app->handle(['greet', 'Мир'], $output);

echo $output->fetch(); // Привет, Мир

Строковые сигнатуры, значения по умолчанию и справка

<?php

use CloudCastle\Command\Application;
use CloudCastle\Command\Contract\ConfigurableCommand;
use CloudCastle\Command\HelpCommand;
use CloudCastle\Command\Input;
use CloudCastle\Command\InputDefinition;
use CloudCastle\Command\Output;
use CloudCastle\Command\Signature;

final class DeployCommand implements ConfigurableCommand
{
    public function getName(): string { return 'app:deploy'; }
    public function getDescription(): string { return 'Разворачивает сборку'; }

    public function definition(): InputDefinition
    {
        // Декларативная сигнатура вместо ручных Argument/Option.
        return Signature::define('deploy {target} {--f|format=json : Формат отчёта}');
    }

    public function execute(Input $input, Output $output): int
    {
        $output->writeln($input->getArgument(0) . ' / ' . $input->getOption('format'));

        return 0;
    }
}

$app = new Application();
$app->add(new DeployCommand());
$app->add(new HelpCommand($app->registry()));
$app->registry()->alias('d', 'app:deploy');           // псевдоним
$app->before(static fn (string $name) => error_log("start: $name")); // хук

$output = new Output();
$app->handle(['app:deploy', 'prod', '-f=yaml'], $output); // prod / yaml
$app->handle(['app:deploi'], $output);                    // подсказка: app:deploy
$app->handle(['help', 'app:deploy'], $output);            // справка по сигнатуре

Возможности

  • Реестр команд по имениadd(), has(), get(), names(); запуск по имени с кодом завершения; перезапись одноимённых.
  • Псевдонимыregistry()->alias('b', 'build'): короткие имена, не засоряющие список команд.
  • Ленивые фабрикиregistry()->factory('build', fn): команда создаётся при первом обращении (аналог CommandLoader), экономит время и память.
  • Команды из замыканийcommand('name', fn, 'описание'): команда без отдельного класса.
  • Строковые сигнатурыSignature::define('deploy {target} {--f|format=json}'): декларативное объявление входа одной строкой.
  • Определения входаArgument/Option с проверкой обязательных, значениями по умолчанию, short-опциями (-f--format), отрицаемыми флагами (--no-cache) и терминатором --.
  • Подсказки при опечатке — «возможно, вы имели в виду…» по расстоянию Левенштейна; скрытые команды не раскрываются.
  • Хуки жизненного циклаbefore(), after(), onError() вокруг запуска.
  • Встроенные list/help/completion — список с группировкой по пространству имён, справка по сигнатуре, автодополнение имён для оболочки.
  • Скрытые командыHiddenCommand не попадает в список и автодополнение.
  • Fail-safe запуск из argv — неизвестная команда, непройденная проверка и исключение самой команды не роняют процесс: сообщение в поток ошибок, код 1.
  • Буферизованный раздельный выводOutput копит вывод и ошибки отдельно (fetch()/fetchErrors()), упрощая тестирование без глобального состояния.
  • Красивый вывод из коробкиOutput реализует контракт cloud-castle/cli, поэтому ANSI-стили, таблицы и рамки пишутся прямо в вывод команд; встроенный list умеет цветной режим. Ленивое создание команд из контейнера — cloud-castle/di. Единственная runtime-зависимость — cloud-castle/cli.

Сравнение с аналогами

Сравнение — с раннерами и обработчиками CLI-ввода: symfony/console, laravel/artisan, minicli, mnapoli/silly, splitbrain/php-cli, nette/command-line. Оформление вывода (цвета, таблицы, прогресс-бар, интерактив) вынесено в cloud-castle/cli и здесь не сравнивается. Все таблицы содержат графу 🏆 Победитель.

Функциональность

Возможностьcommandsymfony/consolelaravel/artisanminiclimnapoli/sillysplitbrain/php-cli🏆 Победитель
Реестр команд по имени⚠️
Псевдонимы команд
Ленивые фабрики команд
Команды из замыканий⚠️
Строковые сигнатуры входа
Определения аргументов/опций
Отрицаемые флаги + терминатор --⚠️
Подсказки при опечатке
Хуки жизненного цикла⚠️
Встроенные list/help/completion⚠️
Скрытые команды
Буферизованный раздельный вывод⚠️⚠️⚠️🏆 command
Красивый вывод из коробки (стили, таблицы)⚠️⚠️⚠️🏆 command
Итого возможностей раннера13/1310/1312/133/1310/133/13🏆 command

command — единственный, кто закрывает объединение раннер-возможностей всех аналогов, сохраняя единственную инфраструктурную зависимость (cloud-castle/cli), уникальный тестируемый буфер вывода и красивое оформление из коробки.

Производительность (2000 итераций, PHP 8.1.34)

БиблиотекаВремя, мсОтносительно command🏆 Победитель
cloud-castle/command0.0013🏆
splitbrain/php-cli0.0015— *
nette/command-line0.0024— *
minicli/minicli0.0240×18.5
symfony/console0.1386×106.6
mnapoli/silly0.1634×125.7

Потребление памяти (прирост на запуск)

БиблиотекаПамять, КБ🏆 Победитель
cloud-castle/command0.1🏆
splitbrain/php-cli0.1
nette/command-line0.1
minicli/minicli0.1
symfony/console16.4
mnapoli/silly20.4

* — парсеры ввода (неполный цикл), вне ранжирования.

Числа — из реального изолированного прогона benchmarks/compare.php (регистрация, разбор ввода и запуск, 2000 итераций, без Xdebug): XDEBUG_MODE=off php benchmarks/compare.php. Таблицы обновляются автоматически: composer docs:bench. splitbrain/php-cli и nette/command-line по модели — парсеры/single-command: они разбирают ввод, но исполнение делегируют коду приложения, поэтому их числа — нижняя оценка полного цикла (в их пользу); command всё равно быстрее и легче.

Безопасность

Критерийcommandsymfony/consolelaravel/artisanminiclimnapoli/silly🏆 Победитель
Строгий вход: срез необъявленных опций⚠️⚠️⚠️🏆 command
Разделение потоков вывода и ошибок⚠️
Fail-safe: исключения не роняют процесс⚠️
Неутечка скрытых команд в подсказках⚠️⚠️🏆 command
Отсутствие глобального состояния⚠️⚠️⚠️🏆 command
Минимальная поверхность атаки⚠️🏆 command/minicli

Качество кода

Метрикаcommandsymfony/consolelaravel/artisanminicli🏆 Победитель
PHPStanmax + strict-rules~level 5~level 5базовый🏆 command
PsalmerrorLevel 1не заявленне заявленне заявлен🏆 command
Покрытие тестами100% / файлвысокоевысокоесреднее🏆 command
Мутационное тестирование (MSI)100%не публикуетсяне публикуетсяне публикуется🏆 command
Runtime-зависимостей1 (cli)3+много0🏆 minicli

Плюсы и минусы

Плюсы:

  • Быстрее и легче всех сравниваемых — подтверждено реальными бенчмарками (см. таблицу выше), near-zero память на запуск.
  • Суперсет раннер-возможностей без привязки к фреймворку: сигнатуры, замыкания, ленивые фабрики, подсказки, хуки, автодополнение.
  • Красивый вывод из коробки — ANSI-стили, таблицы и рамки через cloud-castle/cli пишутся прямо в вывод команд; безопасный строгий вход и fail-safe по умолчанию.
  • Тестируемость — буферизованный раздельный вывод, отсутствие глобального состояния; 100% покрытие и 100% MSI на самом пакете.

Минусы (честно):

  • Моложе и менее распространён, чем symfony/console и laravel/artisan — меньше готовых интеграций и статей. Это единственный существенный компромисс.
  • Одна инфраструктурная зависимостьcloud-castle/cli (оформление вывода) той же экосистемы; для абсолютного нуля зависимостей уместнее minicli.
  • Нет привязки к конкретному фреймворку — by design; для глубокой интеграции с Laravel/Symfony их родные раннеры удобнее.

Рекомендации по применению

  • Идеально: CLI-утилиты и консольные точки входа микросервисов, воркеры и cron-задачи, встраиваемые раннеры внутри библиотек — везде, где важны быстрый старт, малый вес и красивый вывод из коробки.
  • С cloud-castle/cli: утилиты с богатым выводом (цвета, таблицы, прогресс, интерактив) — экосистема ставится одной зависимостью.
  • symfony/console, laravel/artisan — предпочтительнее при глубокой интеграции с их экосистемами (бандлы, DI-контейнер фреймворка, планировщик).
  • minicli — для сверхминималистичных скриптов без определений входа и справки.

Разработка

composer install
composer check       # линтеры + статический анализ + тесты
composer fix         # автоисправления (Rector, PHP CS Fixer, PHPCBF)
composer ci          # полный CI-пайплайн локально
composer docs:bench  # пересобрать таблицы производительности в документации

Полный список команд с описаниями: composer run-script --list.

Документация

Лицензия

MIT © CloudCastle (alex-4-17@yandex.ru)

🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano