direnv + brew-php-switcherでPHPのバージョンを切り替える
What'S?
brewで複数のPHPバージョンをインストールして使っています。
phpenvも試したのですが依存関係を見つけてはinstallする、というのに疲れて続きませんでした...。
PythonやJavaScriptのようにPHPもプロジェクトごとにバージョン管理できればよいのになぁ...。
数年ぶりにPHP: the Right Wayを読んだところ、brew-php-switcherが紹介されており、これでイケそうなのでdirenvと組み合わせてみました。
requirements
- Mac
- brew
- direnv
- brew-php-switcher
現状、以下のようになっています。
バージョンの記載がないphpは、PHP 8.1です。
brew list | grep php
brew-php-switcher
php
php@8.0
.envrc
さっそく、.envrcに以下を書き込みます。
使用しているPHPのバージョンが8.0と8.1のみなので↓こんなです。
必要に応じてgrepのパターン部分を修正ください。
関数化してdirenvrcに書き、.envrcでは呼び出すだけにするとさらにスッキリしますが、自分の環境ではまだそこまでは不要そうなので愚直に各.envrcに書きます。
if type brew-php-switcher &>/dev/null; then
actual_php_version=$(/usr/local/bin/php --version \
| grep -m 1 -o "PHP 8.[0-9]" \
| cut -d' ' -f2)
expect_php_version=$(jq -r .require.php <composer.json \
| cut -d'|' -f1 \
| grep -o "8\.[0-9]")
[[ "$actual_php_version" != "$expect_php_version" ]] && brew-php-switcher "$expect_php_version" -s
fi
動作検証
PHP 8.1が有効な状態でPHP 8.0を使用しているプロジェクトを開いた際にバージョンが切り替わるか試してみます。
jq -r .require.php <composer.json | grep -o "8.[0-9]"
8.0
❯ php -v
PHP 8.1.2 (cli) (built: Jan 21 2022 04:47:46) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2, Copyright (c), by Zend Technologies
.envrcを修正して、direnv allow
します。
direnv allow
direnv: loading ~/src/github.com/watarukura/php-sample-project/.envrc
direnv: ([/usr/local/bin/direnv export fish]) is taking a while to execute. Use CTRL-C to give up.
Switching to php@8.0
Switching your shell
Unlinking /usr/local/Cellar/php@8.0/8.0.15.reinstall... 0 symlinks removed.
Unlinking /usr/local/Cellar/php/8.1.2.reinstall... 24 symlinks removed.
Linking /usr/local/Cellar/php@8.0/8.0.15.reinstall... 25 symlinks created.
If you need to have this software first in your PATH instead consider running:
echo 'fish_add_path /usr/local/opt/php@8.0/bin' >> ~/.config/fish/config.fish
echo 'fish_add_path /usr/local/opt/php@8.0/sbin' >> ~/.config/fish/config.fish
All done!
direnv: export ~XPC_SERVICE_NAME
php -v
PHP 8.0.15 (cli) (built: Jan 21 2022 04:49:41) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.15, Copyright (c) Zend Technologies
with Zend OPcache v8.0.15, Copyright (c), by Zend Technologies
無事に切り替わりました!
もう一度実行してみます。
❯ direnv allow
direnv: loading ~/src/github.com/watarukura/php-sample-project/.envrc
direnv: export ~XPC_SERVICE_NAME
何も起こりません。成功のようです。
参考
手動でPHP 8.0と8.1を切り替えるfishスクリプトを書いて使っていたのですが、自動化できて不要になりました。
これで、来る8.2以降への切り替えの際も困らずに済みそうです。
供養においておきます。
function php80
if contains "8.1" (/usr/local/bin/php --version | /usr/local/bin/ggrep -m 1 -oP "PHP 8.[0-9]" | cut -d' ' -f2)
brew unlink php && brew link --force --overwrite php@8.0
else
echo "already php8.0"
end
end
function php81
if contains "8.0" (/usr/local/bin/php --version | /usr/local/bin/ggrep -m 1 -oP "PHP 8.[0-9]" | cut -d' ' -f2)
brew unlink php@8.0 && brew link --force --overwrite php
else
echo "already php8.1"
end
end
2022/03/06 追記
PECL installしたときにPECLやphpizeに/usr/local/Cellar/php@8.0/8.0.16/bin/php is not found
って怒られるので、原因を調べてみました。
brewで再インストールすると、バージョン番号.reinstallっていうディレクトリ名にインストールされる模様。
PECLとphpizeを書き換えてやると無事に動きました。
もっとよい方法がありそうですが..。
❯ which php
/usr/local/bin/php
❯ ls -l /usr/local/bin/php
lrwxr-xr-x 1 watarukura admin 42 3 2 05:58 /usr/local/bin/php -> ../Cellar/php@8.0/8.0.16.reinstall/bin/php
❯ which pecl
/usr/local/bin/pecl
❯ which phpize
/usr/local/bin/phpize
❯ sudo sed -i.org -e 's/8.0.16/8.0.16.reinstall/g' /usr/local/bin/pecl
❯ sudo sed -i.org -e 's/8.0.16/8.0.16.reinstall/g' /usr/local/bin/phpize
❯ diff -u /usr/local/bin/pecl.org /usr/local/bin/pecl
--- /usr/local/bin/pecl.org 2022-03-06 13:27:42.073462374 +0900
+++ /usr/local/bin/pecl 2022-03-02 15:57:12.987867522 +0900
@@ -4,10 +4,10 @@
if test "x$PHP_PEAR_PHP_BIN" != "x"; then
PHP="$PHP_PEAR_PHP_BIN"
else
- if test "/usr/local/Cellar/php@8.0/8.0.16/bin/php" = '@'php_bin'@'; then
+ if test "/usr/local/Cellar/php@8.0/8.0.16.reinstall/bin/php" = '@'php_bin'@'; then
PHP=php
else
- PHP="/usr/local/Cellar/php@8.0/8.0.16/bin/php"
+ PHP="/usr/local/Cellar/php@8.0/8.0.16.reinstall/bin/php"
fi
fi
@@ -16,12 +16,12 @@
INCDIR=$PHP_PEAR_INSTALL_DIR
INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR"
else
- if test "/usr/local/Cellar/php@8.0/8.0.16/share/php@8.0/pear" = '@'php_dir'@'; then
+ if test "/usr/local/Cellar/php@8.0/8.0.16.reinstall/share/php@8.0/pear" = '@'php_dir'@'; then
INCDIR=`dirname $0`
INCARG=""
else
- INCDIR="/usr/local/Cellar/php@8.0/8.0.16/share/php@8.0/pear"
- INCARG="-d include_path=/usr/local/Cellar/php@8.0/8.0.16/share/php@8.0/pear"
+ INCDIR="/usr/local/Cellar/php@8.0/8.0.16.reinstall/share/php@8.0/pear"
+ INCARG="-d include_path=/usr/local/Cellar/php@8.0/8.0.16.reinstall/share/php@8.0/pear"
fi
fi
❯ diff -u /usr/local/bin/phpize.org /usr/local/bin/phpize
--- /usr/local/bin/phpize.org 2022-03-06 13:27:16.089971124 +0900
+++ /usr/local/bin/phpize 2022-03-02 15:57:49.274987158 +0900
@@ -1,8 +1,8 @@
#!/bin/sh
# Variable declaration
-prefix='/usr/local/Cellar/php@8.0/8.0.16'
-datarootdir='/usr/local/Cellar/php@8.0/8.0.16/share'
+prefix='/usr/local/Cellar/php@8.0/8.0.16.reinstall'
+datarootdir='/usr/local/Cellar/php@8.0/8.0.16.reinstall/share'
exec_prefix="`eval echo ${prefix}`"
phpdir="`eval echo ${exec_prefix}/lib/php`/build"
includedir="`eval echo ${prefix}/include`/php"
@@ -152,7 +152,7 @@
phpize_replace_prefix()
{
$SED \
- -e "s#/usr/local/Cellar/php@8.0/8.0.16#$prefix#" \
+ -e "s#/usr/local/Cellar/php@8.0/8.0.16.reinstall#$prefix#" \
< "$phpdir/phpize.m4" > configure.ac
}
PECL、phpizeは両方ともシェルスクリプトなんですね。初めて知りました。
❯ pecl install --configureoptions 'enable-sockets="yes" enable-openssl="yes" enable-http2="yes" enable-mysqlnd="yes" enable-swoole-json="yes" enable-swoole-curl="yes"' openswoole-4.10.0
❯ php --ri openswoole
openswoole
Open Swoole => enabled
Author => Open Swoole Group <hello@openswoole.com>
Version => 4.10.0
Built => Mar 6 2022 13:08:25
coroutine => enabled with boost asm context
kqueue => enabled
rwlock => enabled
sockets => enabled
openssl => OpenSSL 1.1.1m 14 Dec 2021
dtls => enabled
http2 => enabled
json => enabled
curl-native => enabled
pcre => enabled
zlib => 1.2.11
brotli => E16777225/D16777225
mysqlnd => enabled
async_redis => enabled
Directive => Local Value => Master Value
swoole.enable_coroutine => On => On
swoole.enable_library => On => On
swoole.enable_preemptive_scheduler => Off => Off
swoole.display_errors => On => On
swoole.use_shortname => On => On
swoole.unixsock_buffer_size => 262144 => 262144
openswooleをinstallしてみました。無事にinstallできたようです。
Discussion