Macで複数バージョンのPHPを楽に使い分ける
PHP Advent Calendar 2023 の15日目の記事です!🎄✨
はじめに
Macで複数バージョンのPHPを使い分けるのって意外と難しくないですか?
Docker経由でしかPHPを使わないみたいな猛者スタイルで行ければいいのかもしれませんが、パフォーマンスや開発体験の問題からローカルのPHPを使いたい事情もあると思います。
phpenv と .phpenv-version
ファイルを併用すればディレクトリごとに使用するPHPバージョンを指定することもできますが、このソリューションはいざ導入しようとすると Yak Shavingの嵐が待っていて(実体験) 非常に面倒だったりします。
というわけで、本稿では僕がMacのローカル環境で複数バージョンのPHPを楽に使い分けるために実際にやっていることをサクッとまとめてお伝えしたいと思います。
PHPのインストール
まず、PHPのインストール自体は普通にHomebrewで行っています。
shivammathur/php
タップ にて主要なマイナーバージョンは一通り配布されているので、どうしてもパッチバージョンまで指定したいという特殊なニーズがない限りは何も困ることはありません。
もしどうしてもパッチバージョンまで指定した環境が手元に必要な場合は、その環境だけはDockerで構築すればいいやというスタンスです。
後述する方法でディレクトリごとにPHPバージョンを切り替えて使い分けるので、以下のような感じで、手元に必要なすべてのバージョンのPHPをインストールします。
$ brew install shivammathur/php/php@7.4
$ brew install shivammathur/php/php@8.0
$ brew install shivammathur/php/php@8.1
$ brew install shivammathur/php/php@8.2
$ brew install shivammathur/php/php@8.3
システムのデフォルトとして使いたいバージョンをリンクしておきます。
$ brew link --force --overwrite shivammathur/php/php@8.3
各バージョンのPHPへのPHP拡張のインストール
Homebrewでインストール
PHP拡張のインストールもほぼHomebrewで行っており、PECLパッケージを手動でインストールすることはほとんどありません。
shivammathur/extensions
タップ にて主要なPHP拡張はほとんど入手可能です。
例えば以下のような感じで、インストール済みのPHPバージョンごとに、追加したいPHP拡張をインストールします。
$ brew install shivammathur/extensions/apcu@7.4
$ brew install shivammathur/extensions/xdebug@7.4
$ brew install shivammathur/extensions/apcu@8.0
$ brew install shivammathur/extensions/xdebug@8.0
$ brew install shivammathur/extensions/apcu@8.1
$ brew install shivammathur/extensions/xdebug@8.1
$ brew install shivammathur/extensions/apcu@8.2
$ brew install shivammathur/extensions/xdebug@8.2
$ brew install shivammathur/extensions/apcu@8.3
$ brew install shivammathur/extensions/xdebug@8.3
PECLでインストール
shivammathur/extensions
タップで配布されていないPHP拡張が必要な場合は、PECLパッケージを手動でインストールします。
# PHP 7.4に対応しているxdebugの最新版は3.1.6
$ $(brew --prefix)/opt/php@7.4/bin/pecl install xdebug-3.1.6
xdebugは
shivammathur/extensions
タップで配布されていますが、適当な例が思いつかなかったので🙏
pecl install
したあとは必要に応じて php.ini
を修正します。PHP拡張によっては pecl install
中に php.ini
の先頭や末尾に extension=...
を自動で追記してくれるものもあるので要注意です。
$ vi $(brew --prefix)/etc/php/7.4/php.ini
# 例
zend_extension=xdebug.so
xdebug.mode=develop,debug
xdebug.start_with_request=yes
なお、pecl
コマンドの実行には前提として pkg-config
zlib
がインストールされている必要がありますので、事前に以下を実行しておきましょう。
$ brew install pkg-config zlib
ディレクトリごとにPHPバージョンを切り替える
ディレクトリごとのPHPバージョンの切り替えには direnv というツールを活用します。
まず、direnv自体をHomebrewでインストールします。
$ brew install direnv
$ echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
次に、PHPバージョンを指定したいディレクトリの直下に、以下のような内容の .envrc
というファイルを作成します。
export PATH=$(brew --prefix)/opt/php@8.1/bin:$PATH
最後に、同ディレクトリ直下で以下のコマンドを実行してdirenvを有効化すれば完了です。
$ direnv allow
direnv: loading /path/to/dir/.envrc
direnv: export ~PATH
これで、同ディレクトリ配下ではPHP 8.1が優先的に(システムのデフォルトはPHP 8.3であるにもかかわらず)使用されます。
$ php -v
PHP 8.1.26 (cli) (built: Nov 21 2023 21:53:48) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.26, Copyright (c) Zend Technologies
with Xdebug v3.2.1, Copyright (c) 2002-2023, by Derick Rethans
with Zend OPcache v8.1.26, Copyright (c), by Zend Technologies
php.ini
を上書きする
ディレクトリごとに direnvを有効化したディレクトリの直下に php.ini
を置くことで、同ディレクトリ配下におけるPHP実行時設定を必要に応じて上書きするという運用もおすすめです。(多くの場合、プロジェクトごとに php.ini
に設定したい内容が多少異なるでしょうから)
.envrc
に以下の一行を追記するだけで簡単に実現できます。
export PATH=/opt/homebrew/opt/php@8.3/bin:$PATH
+ export PHP_INI_SCAN_DIR=:$(pwd)
.envrc
を変更したら、再度 direnv allow
が必要なので要注意です。(CLIで何か作業しようとするとエラーが出力されるのですぐに気づけますが)
$ direnv allow
direnv: loading /path/to/dir/.envrc
direnv: export +PHP_INI_SCAN_DIR ~PATH
ちなみに:Symfony CLIとの比較
ちなみに、Symfony CLI が提供する symfony
コマンドには、プロジェクトルートの .php-version
ファイルでPHPバージョンを指定したり、プロジェクトルートの php.ini
ファイルで symfony
コマンド経由のプロセスのPHP実行時設定を上書きできたり という便利な機能があるので、Symfonyプロジェクトにおいてはdirenvの代わりにこれを使っても似たような体験が得られそうですが、composer
コマンドや任意のPHPスクリプトをCLIで実行する際にもいちいち symfony composer
や symfony php
とタイプしなければならず、だいぶ面倒なので僕は常にdirenvを使った運用に統一しています。
おまけ:ディレクトリごとにComposerのバージョンを切り替える(追記あり)
特定のディレクトリで特定のバージョンのComposerを使いたいことがたまにあります。(チーム開発プロジェクトで、composer.lock
をバージョン管理していて、Composerのバージョンの違いによって動作に影響があったり、composer.lock
に差分が出てしまったりするケース)
これに関しては残念ながらスマートな解決策はないので、プロジェクトルートディレクトリ直下に使いたいバージョンのバイナリを置いておいて、direnvでプロジェクトルートディレクトリにPATHを通す、という原始的な方法をとっています😓
Composerの各バージョンのバイナリは https://getcomposer.org/download/ ここからダウンロードできます。
例えば 2.6.6 を使いたい場合なら、
$ wget https://getcomposer.org/download/2.6.6/composer.phar
$ mv composer{.phar,}
$ chmod +x composer
でディレクトリ直下にバイナリを置いて、.envrc
に以下を追記し、direnv allow
します。
export PATH=/opt/homebrew/opt/php@8.3/bin:$PATH
+ export PATH=$(pwd):$PATH
export PHP_INI_SCAN_DIR=:$(pwd)
これで、このディレクト配下では、composer
とタイプすると、今しがた配置したバイナリが優先的に使用されるようになります。
$ composer -V
Composer version 2.6.6 2023-12-08 18:32:26
ダウンロードした composer
ファイルをバージョン管理したくない場合は .gitignore
に追記しておきましょう。
2024-06-06 追記
Composerの公式サイトで配布されている各バージョンを個別にインストールできるHomebrew tapを作りました。
https://github.com/ttskch/homebrew-composer
これを使えば、例えば 2.6.6 を使いたい場合なら、
$ brew install ttskch/composer/composer@2.6.6
でインストールした上で、.envrc
に以下を追記し、direnv allow
すればOKです。
export PATH=/opt/homebrew/opt/php@8.3/bin:$PATH
+ export PATH=/opt/homebrew/opt/composer@2.6.6/bin:$PATH
export PHP_INI_SCAN_DIR=:$(pwd)
これで、このディレクト配下では、composer
とタイプすると、composer@2.6.6
のバイナリが優先的に使用されるようになります。
$ composer -V
Composer version 2.6.6 2023-12-08 18:32:26
便利ですね😋
ちなみに、https://github.com/ttskch/homebrew-composer はGitHub Actions経由で毎日自動更新するようにしてあるので時間が経っても陳腐化しません。よろしければご活用ください。
おわりに
というわけで、Homebrewとdirenvを使ってMacで複数バージョンのPHPを楽に使い分ける方法について解説してみました。
少しでもお役に立てば幸いです🍵
Discussion