👌

Symfony Consoleで学ぶ「CLIツールの入口構造」

に公開

〜 bin/console がコマンドを呼ぶまでを読み解く 〜

PHPのOSSを読むとき、「どこが入口なのか分からない」が最大の壁になりがちです。
特に phpstan のように CLIで動くツールは、CLIの入口構造が分かると理解が一気に進みます。

この記事では、Symfony Console(symfony/console)を題材にして、

  • CLIツールがどう起動されるか
  • コマンドがどう登録されて実行されるか
  • OSSを読むときどこを見ればいいか

を整理します。

1. なぜ Symfony Console を読むのが良いのか?

Symfony Console は、PHPのCLIツール実装の「王道」です。

  • Laravelの artisan は Symfony Console ベース
  • phpstan や php-cs-fixer も同系統の構造
  • CLIの設計パターンが綺麗に抽象化されている

つまり Symfony Console を読めるようになると、

✅ Laravelの artisan の内部が読める
✅ phpstan の入口が追える
✅ 自分でCLIツールを作れる

という状態になれます。

2. CLIツールの “入口” はどこ?

結論から言うと、CLIツールの入口はほぼ必ず次のどれかです。

✅ A. bin/ ディレクトリ

例:bin/console / vendor/bin/phpstan など
→ 直接実行されるスクリプトがある

✅ B. composer.json の bin

composer.json に "bin": ["bin/xxxx"] がある
→ vendor/bin/xxxx が作られる

✅ C. READMEの実行例

READMEに php bin/console ... と書いてある
→ そこから入口を逆算できる

3. OSSを読む最初の一手:composer.json を見る

Symfony Console を読むときも、最初に見るべきは composer.json です。

✅ ここで見たいポイント(OSS読解の基本)

  • autoload(src がどこに紐づくか)
  • dependencies(何に依存しているか)
  • require PHP version(対応範囲)
  • bin があるかどうか(ある場合はCLI入口)

Symfony Console 自体は「ライブラリ」であって、単体で bin/console は持ちません。
ですが、SymfonyプロジェクトやLaravelなどが Console を使って bin/console を作る。

なので Console の理解では次が重要になります:

「bin/console は自分のアプリ側にある」
「Console は CLIの仕組みを提供する側」

4. CLIツールは何をしているのか(全体像)

CLIツールの処理は だいたい4ステップにまとまります。

✅ CLIが動くときの4ステップ

  1. 入口スクリプトが起動する

    • bin/console が実行される
  2. Application(コンテナ)が作られる

    • new Application() など
  3. Command が登録される

    • $app->add(new FooCommand())
    • もしくは自動登録(DIなど)
  4. ユーザー入力に応じて Command が選ばれて実行される

    • $app->run() の中で
    • 入力解析 → コマンド選択 → execute()

つまり CLIを読むときの一番の目的は:

「入口 → Application → Command登録 → 実行」

この流れがどこで起きているかを見つけること。

5. Symfony Consoleで “役者” を押さえる

Symfony Console の理解を一気に進めるには、重要クラスを3つ覚えるだけでOKです。

✅ 重要クラス3つ

① Symfony\Component\Console\Application

  • CLIツールの “本体”
  • コマンド一覧を保持する
  • 入力からコマンドを選んで実行する

② Symfony\Component\Console\Command\Command

  • 各コマンドのベースクラス
  • configure() と execute() が重要

③ Symfony\Component\Console\Input / Output

  • 入力(引数・オプション)と出力(標準出力)の抽象化

6. 実際に「入口の流れ」を追うときの読み方

ここからが、OSS読解の実践パートです。

✅ 手順:まず “呼ばれている順” に追う

CLIの入口側(bin/console)にはだいたいこういう流れがあります:

  1. autoload 読み込み
  2. Application生成
  3. コマンド登録
  4. run()

この「見慣れた形」を探すだけで良い。

✅ 入口スクリプトで探すべきキーワード

  • require __DIR__ . '/../vendor/autoload.php'
  • new Application(...)
  • $application->add(...)
  • $application->run()

✅ $application->run() の中で何が起きる?

OSSを読むときは run() の中身を全部理解しようとしないで、

  • 入力がパースされる場所
  • コマンドを選ぶ場所
  • コマンドを実行する場所

だけ追えばOK。

ここで「CLIツールの骨格」が掴めます。

7. Commandの読み方:configure → execute が仕様

コマンドクラスを読みに行くと、

  • configure() が “使い方の定義”
  • execute() が “処理本体”

になっています。

✅ configure() が何をしているか

  • コマンド名
  • 説明
  • 引数(arguments)
  • オプション(options)

つまり configure() は CLIの仕様書です。

✅ execute() が何をしているか

  • 実際のビジネスロジック
  • サービス呼び出し
  • 入出力の処理

8. Symfony Consoleを読むことで得られる「転用可能な知識」

Symfony Consoleの構造理解は、そのまま以下に転用できます。

✅ Laravel artisan の読解

  • artisan は結局 Application と Command の上に成り立ってる
  • Illuminate\Console\Application は Symfony Console を拡張している

✅ phpstan の入口理解

  • phpstanは vendor/bin/phpstan を起点に
  • Console の Application と同じ思想で動く
  • コマンドの登録と実行のパイプラインが似ている

✅ 自作CLIツール設計

  • Commandに責務を閉じ込める
  • Applicationは “選択と実行” のみに集中
  • 入出力は抽象化する

9. OSS読解のコツ(初心者がハマるポイント回避)

❌ すべての内部クラスを理解しようとしない

Consoleは内部で色々やってますが、

  • アプリとして使う側が触るのは Application と Command が中心
  • そこを起点に読むと迷わない

✅ tests も “コマンドの仕様書”

Symfony Consoleにも tests があり、
「入力したときどういう結果になるべきか」が書かれています。

OSSは READMEより testsが真実なので、
慣れてきたら testsから読むのもおすすめ。

まとめ:Symfony Consoleで押さえるべき最短ルート

✅ 入口スクリプト(bin/console / vendor/bin/xxx)を見る
✅ Application の生成・run() を見る
✅ Command の configure/execute を見る
✅ tests で挙動を確認する

Discussion