composer での require と require-dev キー
PHPで広く使われている依存性マネージャの composer には、昨今の他の言語で用いられているツール同様に、依存性を設定するキーとして
require
と require-dev
が存在します。
このキー欄にはそれぞれプロジェクトが依存する、PHPのバージョン・個々のPHP拡張・ベンダーパッケージとそのバージョン が指定できます。 普段PHPを利用する開発者のみなさんは、以下の通り依存性の追加コマンドを追加されてるかと思います。
composer require monolog/monolog # ロガーとしてmonologが必要 composer require --dev phpunit/phpunit # 開発時にテイスティングツールとしてPHPUnitが必要
require-dev
の特徴として、
composer install --no-dev
にてプロジェクトでのインストール時に対象外となる。- 依存指定するパッケージの require 指定時に、そのパッケージ先の require-dev は対象外となる。
が挙げられます。
本番リリース時のデプロイケース
開発用パッケージについては、本番の実行環境については必要ありませんので、デプロイパイプラインでは本番のみ --no-dev
と指定しているプロジェクトも多いかと思います。
例えば、Google App Engine flex の実行Dockerイメージを作成する php-docker は、composer.jsonがプロジェクトルートに含まれていれば、指定されたPHP拡張のインストールも含め行ってくれますが、デフォルトでは、
'COMPOSER_FLAGS' => '--no-dev --prefer-dist',
と--no-dev
でのインストールになります。
require-dev が依存するパッケージの問題
この 本番と開発環境でインストールされるパッケージが異なる点について問題となるのが、dev指定のパッケージが依存するパッケージをプロダクションコードにて利用している場合です。
例えば、friendsofphp/php-cs-fixer
を利用している場合 symfony/process
がdev依存性でありますが、それに気づかず、Symfony\Component\Process\Process
クラスを用いる改修を行い、require
設定をsymfony/process
に行っていない場合にクラスが見つからずエラーとなってしまいます。
composer-require-checker による検出
昨年のPHPカンファレンス 2019 でも紹介しましたが、maglnet/composer-require-checker
を用いると、composer.jsonでrequire定義されていないシンボル(クラスやPHP拡張の関数) を検出することができます。
実行方法としては、インストール後プロジェクトのルートディレクトリにて、
composer-require-checker check composer.json
とすることで、以下のような出力を得ることができます。
ComposerRequireChecker 2.1.0@0c66698d487fcb5c66cf07108e2180c818fb2e72 The following unknown symbols were found: +------------------------------------------------------------+--------------------+ | unknown symbol | guessed dependency | +------------------------------------------------------------+--------------------+ | Aura\Router\Router | | | Aura\SqlQuery\Common\InsertInterface | | | Aura\SqlQuery\Common\SelectInterface | | | Aura\Sql\ExtendedPdoInterface | | | BEAR\AppMeta\AbstractAppMeta | | | BEAR\AppMeta\AppMeta | | | BEAR\AppMeta\Meta | | | ctype_digit | ext-ctype | | Doctrine\Common\Cache\Cache | |
それぞれのクラス名については、対応するパッケージを追加し、guessed dependency 欄にext-○○○ と記載されている場合はPHP拡張がrequireセクションに足りないので追加します。
CIでの検出
このcomposer-require-checker check
コマンドでのunknown symbolsがなにも検出されなかった場合と検出時のexitコードは分かれてますので、CIに組み込むができます。
弊社では GitHub Actionに composer-require-checker のセットアップを行いました。
GitHub Actions での設定例
最近では shivammathur/setup-php@v2 にて、7月21日リリースの2.4.0でtoolsにcomposer-require-checker
が追加されたのでそちらを使うと良いかと思います。
https://github.com/shivammathur/setup-php/releases/tag/2.4.0
設定例としては、.github/workflows/composer-require-checker.yml
に以下の設定を行います。
name: "Composer Require Checker" on: pull_request: push: branches: - "master" jobs: composer-require-checker: name: composer-require-checker check runs-on: ubuntu-latest steps: - name: "Checkout" uses: actions/checkout@v2 - name: "Install PHP" uses: shivammathur/setup-php@v2 with: tools: composer-require-checker - name: "Get composer cache directory" id: composercache run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: "Cache composer dependencies" uses: actions/cache@v2 with: path: ${{ steps.composercache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer- - name: "Install dependencies" run: | composer install --no-progress --no-scripts --no-dev - name: "Run composer-require-checker check" run: composer-require-checker check composer.json
余談ですが、 GitHub Actionsの場合は、 「Create Status badge」から以下のようなステータスバッジのマークダウンがコピーできますので、
![Composer Require Checker](https://github.com/{ベンダー}/{リポジトリ}/workflows/Composer%20Require%20Checker/badge.svg)
README.md に追加して確認できるようにすると、ちょっとだけ安心感が増えるかも知れません。
利用/導入しての感想
composer-require-checkerの利用目的としては、上述に上げました--no-dev
な本番環境へのリリース事後防止が上げらえますが、それ以外にも
- extの指定漏れがなくなるので、途中からの参画メンバには
composer install
で必要な開発環境を確認してもらうことができる。 - 依存パッケージが大多数の場合での、個別のパッケージupdate作業にて依存の確認が分かりやすくなった。
という良かった点があります。
利用されてないパッケージの削除? ~ composer-unused
composer-require-checker の"逆"なツールとして、コードベースでは未使用なrequireパッケージを検出する composer-unused が存在します。
現状では class-string
なクラス名指定箇所に(Foo::class指定ではなく) 文字スカラー値そのままでの指定の場合にもunusedと検出されてしまうので、
現在、弊社のメインプロジェクトではCIには取り組めてないのですが、将来的にはこの点も解消した上で過不足無いパッケージにしていきたいです。