composer をインストールすると、パッケージに含まれる CLI ベースの補助ツールのシンボリックリンクが、自動的に vendor/bin に作られます。
この補助ツールを自分で作る方法について、いろいろと罠にハマったので記録しておきます。
composer.json の bin プロパティに補助ツールのパスを記述します。パスはプロジェクトルートからの相対パスとします。
{ "bin": [ "path/to/bin", "path/to/another", ... ] }
__DIR__ . '/../../../autoload.php'
となり、vendor を含めると
__DIR__ . '/../../../../vendor/autoload.php'
となる.
#!/usr/bin/env php <?php $autoloaders = [ __DIR__ . '/../vendor/autoload.php', // 自プロジェクトからの呼び出し __DIR__ . '/../../../../vendor/autoload.php' // composer インストールされた先からの呼び出し ]; foreach ($autoloaders as $file) { if (file_exists($file)) { define('AUTOLOADER_PATH', $file); break; } } unset($file); require AUTOLOADER_PATH; // Call Main Script Some\Cli\Application::main();
autoloader と同様、コマンドの引数にパスを渡すような場合、実ファイルのパスをベースに解決しようとすると、自身の存在するパスが変化するため、実装が難しい。
このため、getcwd() という関数を使用することでパスの解決を行う。
Phinx では Symfony\Component\Config\FileLocator というパッケージを使って設定ファイルのパスを解決をしている。
https://github.com/cakephp/phinx/blob/master/src/Phinx/Console/Command/AbstractCommand.php
https://github.com/symfony/config/blob/5.3/FileLocator.php
なお、vendor/bin にはシンボリックリンクが作られるが、シンボリックリンクから実行しても、実行した場所のディレクトリ(シンボリックリンクの親ディレクトリ)を得られるため、気にせず実装できる。