hnwの日記

Console Componentを利用したメモ

Console Componentを使った感想を記録しておきます。雑なメモですが、どなたかの参考になれば。

Console Componentとは

Console ComponentはPHPコマンドラインアプリケーション用ライブラリです。コマンドラインオプション解析や、出力に簡単に色をつける機能などを提供しています。


ちなみに、このライブラリはSymfony Componentsに含まれています。SymfonyPHPの有名フレームワークですが、多くの機能をスタンドアロンなライブラリとして切り出しています。Console Componentもその一つということになります。

コマンドラインオプション解析ライブラリとしての特徴

  • 標準的なコマンドラインオプションに対応している
    • short option/long option両対応
    • 値を取らないshort optionを圧縮して指定できる(-v -a -xを-vaxと指定できる)
    • オプションが値を取らない/値が必須/値を指定してもしなくても良い/複数指定できるに対応
  • サブコマンドに対応している
  • ヘルプメッセージ(--helpで出力される内容)を勝手に作ってくれる
  • テストが書きやすい
    • 特定のコマンドラインオプションが指定された状況をテストすることができる

イマイチな点

  • コマンドラインオプション解析だけしたい場合には巨大かつ冗長
    • 必ずCommandクラスを継承したクラスを作らなくてはならない
  • サブコマンド無しのコマンドが標準では作れない
    • 単機能のツールを作る場合でも必ずサブコマンド指定をさせることになる
  • --with-foo,--without-fooのようなオプション指定に標準で対応していない
    • 他言語の同等ライブラリでは真偽値を返してくれるものがあって便利
  • 値を取るオプションの場合に、型の指定ができない
    • 他言語の同等ライブラリでは数値を取るオプションに文字列が来るとエラーにしてくれる、無きゃ無いでいいかも…


上記のうちいくつかは簡単に対応できそうな気もしていますが、「巨大かつ冗長」はどうにもならんと思います。

サンプルコード

以下、Commandクラスを継承したクラスの例です。これをApplicationクラスからadd()で登録して使います。

<?php
namespace Hnw\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;

class ListGithubUsersCommand extends Command
{
    protected function configure()
    {   
        $this->setName('list-github-users')
             ->setDescription("Display GitHub login IDs")
             ->setDefinition(array(
                new InputOption('from', 's', InputOption::VALUE_REQUIRED, 'Start number of the range of GitHub user ID'),
                new InputOption('to', 'e', InputOption::VALUE_REQUIRED, 'Stop number of the range of GitHub user ID'),
                new InputOption('num', null, InputOption::VALUE_REQUIRED, 'Maximum number of login IDs to display', 100),
                new InputOption('token', 't', InputOption::VALUE_REQUIRED, 'Specify GitHub personal access token'),
            ))
            ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $fromId = intval($input->getOption('from'));
        $toId = intval($input->getOption('to'));

        /* 以下、処理の本体を書く */
    }
}


この定義で下記のようなヘルプが出てきます(実際は色つきです)。

Usage:
 list-github-users [-s|--from="..."] [-e|--to="..."] [--num="..."] [-t|--token="..."]

Options:
 --from (-s)           Start number of the range of GitHub user ID
 --to (-e)             Stop number of the range of GitHub user ID
 --num                 Maximum number of login IDs to display (default: 100)
 --token (-t)          Specify GitHub personal access token
 --help (-h)           Display this help message.
 --quiet (-q)          Do not output any message.
 --verbose (-v|vv|vvv) Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
 --version (-V)        Display this application version.
 --ansi                Force ANSI output.
 --no-ansi             Disable ANSI output.
 --no-interaction (-n) Do not ask any interactive question.

まとめ

個人的な認識として、PHPは他の言語と比べると良いコマンドラインオプション解析ライブラリが出てこなかった印象があります。getopt関数か手書きかしか選択肢が無いに等しい状況で、前世紀のCプログラミングのような惨状が続いてきたのではないでしょうか(Console_CommandLineはボチボチ良い印象がありますが、いまどきPEARも無いかなーと思いますし…)。


Console Componentはsymfonyコマンドのサブコマンド的なもの(タスク)を作る仕組みを切り出したもので、書き捨てるくらいのツールに使うには大げさ過ぎると感じます。とはいえ、選択肢が少ない中では有力なライブラリだと言えるのではないでしょうか。また、長くメンテするようなコマンドを作る場合はテスタビリティの高さがメリットになると思います。