🎻

Macで複数バージョンのPHPを楽に使い分ける

2023/12/15に公開

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 composersymfony 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を楽に使い分ける方法について解説してみました。

少しでもお役に立てば幸いです🍵

GitHubで編集を提案

Discussion