【Windows】Scoop で実現する PHP のバージョン切り替え

【Windows】Scoop で実現する PHP のバージョン切り替え

世間でお盆が終わったのかどうかもよくわかっていないくらい世事に疎い kagata です。

今回は、Windows 使いの PHPer として長らく懸案だった「PHP のバージョン切り替え」について、もしかすると便利かもしれない方法を試してみたのでここにご報告申し上げます。

これまでの手法と問題点

開発用の PHP バージョンを切り替える手法は、これまでにもさまざま提案されてきました。大きく分けると、複数の PHP をローカルにインストールするものとリモートの PHP 実行環境を利用するものの2種類が挙げられます。しかし、それぞれ不便なところがあります。

ローカルにインストールする場合

PHP には公式の Windows 向けバイナリがあります。また、Apache や MySQL など各種ミドルウェアをバンドルした XAMPP も昔から親しまれてきました。Windows 上に PHP 実行環境を準備するだけなら、特に難しいことはありません。

しかし、複数バージョンの PHP を使い分けるのは大変です。環境変数やシンボリックリンクやバッチファイルを駆使して、自分が使いたいバージョンの PHP が確実に呼び出せるようにしないといけません。いくつか報告例がある中で、筋がよさそうなのは下の記事かなと思います。

Windows環境のComposerを複数PHPバージョンで使い分ける | そど

Linux や macOS なら、phpenv や phpbrew や direnv などで簡単にバージョン切り替えが実現できます。しかし、いずれも Windows 上で動作させるのは簡単ではありません。Cygwin や MSYS/MinGW でうまいことやっている例はあるようですが、やはりめんどくさそうです。

リモートの実行環境を利用する場合

そういうわけで、PHP の実行環境はリモートに用意する例が増えました。近年のマシンスペック向上に加えて Vagrant が登場したことで、「開発用の仮想環境を必要なだけ立ち上げ、不要になれば捨てる」ということが気軽にできるようになりました。また、AWS などクラウド上に開発サーバーを置いてしまうことも増えてきたと思います。

ただ、ローカルマシンに仮想環境を立ち上げるとなると、それだけリソースを消費します。マシンスペックが向上したとはいえ、プロジェクトを掛け持ちするうちに気がついたらストレージに余裕がなくなっていた…なんてことは今でも時折あります。

また、PHP の実行環境がネットワークの先にあると、IDE などの環境設定が煩雑になったり、レスポンスの遅さが気になったりすることがあります。例えば PhpStorm なら、ファイルの同期、リモートデバッグ、PHP インタプリタなどの設定が増えるでしょう。また、PhpStorm には Composer や PHP_CodeSnifferPHPMD などのコマンドラインツールと連携する機能があります。これらの実行にリモートの PHP インタプリタを使わせることもできますが、ネットワーク環境しだいではレスポンスの遅さが気になることがあります。

Scoop とは

Scoop は Windows 用のパッケージ管理ツールです。全般的な解説は以下の記事が詳しいです。

ScoopでWindowsにおける開発環境構築を最適化しよう | さにあらず

同じく Windows のパッケージ管理ツールである PackageManagement や Chocolatey は以前試したことがありましたが、結局しっくりこなくて最近はご無沙汰でした。Scoop を少し触ってみたところいい感触を得たので、これでローカル PHP のバージョン切り替えができないか試してみることにしました。

Scoop で複数バージョンの PHP アプリ開発環境を構築する

Scoop をインストールする

まずは Scoop をインストールします。PowerShell から次のコマンドを実行しましょう。

PS> iex (new-object net.webclient).downloadstring('https://get.scoop.sh')

環境によっては、次のようなエラーが出ることがあります。

PowerShell requires an execution policy of 'RemoteSigned' to run Scoop.
To make this change please run:
'Set-ExecutionPolicy RemoteSigned -scope CurrentUser'

その場合は、指示のとおり Set-ExecutionPolicy RemoteSigned -scope CurrentUser を先に実行しましょう。わたしは習慣上 Set-ExecutionPolicy RemoteSigned -scope Process としました。こちらでも OK です。

なお、Set-ExecutionPolicy コマンドの意味や使い方については以下の記事が詳しいです。

PowerShellのExecutionPolicyのスコープとかについて詳しく

インストールできたら scoop コマンドを実行してみましょう。次のようにサブコマンドの一覧が表示されれば成功です。

PS> scoop
Usage: scoop <command> [<args>]

Some useful commands are:

alias       Manage scoop aliases
bucket      Manage Scoop buckets
cache       Show or clear the download cache
checkup     Check for potential problems
cleanup     Cleanup apps by removing old versions
config      Get or set configuration values
create      Create a custom app manifest
depends     List dependencies for an app
export      Exports (an importable) list of installed apps
help        Show help for a command
home        Opens the app homepage
info        Display information about an app
install     Install apps
list        List installed apps
prefix      Returns the path to the specified app
reset       Reset an app to resolve conflicts
search      Search available apps
status      Show status and check for new app versions
uninstall   Uninstall an app
update      Update apps, or Scoop itself
virustotal  Look for app's hash on virustotal.com
which       Locate a shim/executable (similar to 'which' on Linux)


Type 'scoop help <command>' to get help for a specific command.

PHP をセットアップする

Scoop がインストールできたら、これを使って PHP をインストールします。

最新の PHP をインストールする

コマンド scoop search で PHP のパッケージを検索してみましょう。

PS> scoop search php
'main' bucket:
    php-nts (7.2.8)
    php (7.2.8)

main というバケットに PHP7.2.8が入っていました。Scoop の「バケット」は、パッケージの配布元を示す情報をまとめたものです。CentOS でお世話になる yum でいうところの「リポジトリ」のようなイメージです。main バケットには、基本的に現時点で最新の PHP が入っているようです。php-nts は非スレッドセーフ版ですね。

次のコマンドで PHP をインストールします。実は main バケットには親切なことに Composer も置いてあります。いっしょにインストールしてしまいましょう。

PS> scoop install php composer

これで、PHP7.2.8がインストールできました。

PS> php -v
PHP 7.2.8 (cli) (built: Jul 18 2018 10:03:03) ( ZTS MSVC15 (Visual C++ 2017) x64 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Xdebug v2.6.1, Copyright (c) 2002-2018, by Derick Rethans

このタイミングで、PHP の設定を確認しておきましょう。設定ファイルは %UserProfile%\scoop\persist\php\cli\php.ini です。

設定を変更したい場合は、ディレクトリ %UserProfile%\scoop\persist\php\cli\conf.d\ に適当な名前の .ini ファイルを置いて、そこに変更内容を記述すれば OK です。

例えば CakePHP アプリケーションを動かしたいなら、次のようにエクステンションの読み込みを追加すればよいでしょう。

extension=mbstring
extension=intl
extension=pdo_sqlite
extension=sqlite3
extension=curl

参考:Custom PHP configuration · lukesampson/scoop Wiki · GitHub

extras バケットを導入する

ところで、先ほど PHP をインストールする際、'php' suggests installing 'extras/vcredist2017' というメッセージが表示されたはずです。これは extras バケットにあるパッケージ vcredist2017 をインストールするようすすめるメッセージです。

メッセージに従って、まずは extras バケットを導入しましょう。yum でいえば remi や epel を追加するようなイメージです。

PS> scoop bucket add extras

extras バケットを導入すると、パッケージ vcredist2017 がインストールできるようになります。ちなみに、これは「Visual Studio 2017 の Microsoft Visual C++ 再頒布可能パッケージ」のことです。公式インストーラーなどでインストール済みなら、この作業は不要です。

PS> scoop install vcredist2017

このコマンドを実行すると、裏側では公式インストーラーをダウンロードして即実行する、という動きをするようです。 scoop uninstall vcredist2017 で、ダウンロードしたインストーラーを削除します。インストールされたランタイムコンポーネント自体はこのコマンドでは削除されず、削除したい場合は Windows の管理画面から作業することになります。

extras バケットには、実は Xdebug も入っています。デバッガーが使いたい場合はインストールしておきましょう。

PS> scoop search xdebug
'extras' bucket:
    php-nts-xdebug (2.6.1-7.2)
    php-xdebug (2.6.1-7.2)
PS> scoop install php-xdebug

これで Xdebug がインストールできました。が、php コマンドを実行するとおかしなことになっています。

PS> php -v
PHP Warning:  Failed loading Zend extension '\' (tried: ext\\ (指定されたモジュールが見つかりません。), ext\php_\.dll ( 指定されたモジュールが見つかりません。)) in Unknown on line 0
PHP 7.2.8 (cli) (built: Jul 18 2018 10:03:03) ( ZTS MSVC15 (Visual C++ 2017) x64 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Xdebug v2.6.1, Copyright (c) 2002-2018, by Derick Rethans

%UserProfile%\scoop\persist\php\cli\conf.d\xdebug.ini を見に行くと、以下のような中身になっています。壊れちゃってますね。

zend_extension=\
C:\Users\kagata\scoop\apps\php-xdebug\current\php_xdebug.dll\

ほんとうはこのあたりを直さないといけないようですが、今回はとりあえず手で次のように修正しました。

zend_extension=C:\Users\kagata\scoop\apps\php-xdebug\current\php_xdebug.dll

旧バージョンの PHP をインストールする

先ほど最新の PHP7.2をインストールしましたが、ときには PHP5.6が使いたいこともあるとしましょう。旧バージョンのパッケージを手に入れるには versions バケットが便利です。

PS> scoop install versions

versions バケットを導入すると、次のような品揃えになりました。PHP5.4以降の各マイナーバージョンの最新版が入っています。

PS> scoop search php
'main' bucket:
    php-nts (7.2.8)
    php (7.2.8)

'extras' bucket:
    appengine-go (1.9.67) --> includes 'php_cli.ps1'
    eclipse-php (4.8.0)
    php-nts-xdebug (2.6.1-7.2)
    php-xdebug (2.6.1-7.2)
    
'versions' bucket:
    php54 (5.4.45)
    php55-xdebug (2.5.5-5.5)
    php55 (5.5.38)
    php56-xdebug (2.5.5-5.6)
    php56 (5.6.37)
    php70-xdebug (2.6.1-7.0)
    php70 (7.0.31)
    php71-xdebug (2.6.1-7.1)
    php71 (7.1.20)

次のコマンドで、PHP5.6 とそれに対応する Xdebug をインストールしましょう。vcredist のインストールを促されたら、あわせてインストールするとよいでしょう。

PS> scoop install php56 php56-xdebug

これで PHP5.6がインストールされました。しかし、いざ PHP5.6を実行しようとすると、どうも様子が変です。

PS> php -v
Failed loading C:\Users\kagata\scoop\apps\php-xdebug\current\php_xdebug.dll
PHP Warning:  PHP Startup: Unable to load dynamic library 'ext\mbstring' - 指定されたモジュールが見つかりません。
 in Unknown on line 0
PHP Warning:  PHP Startup: Unable to load dynamic library 'ext\intl' - 指定されたモジュールが見つかりません。
 in Unknown on line 0
PHP Warning:  PHP Startup: Unable to load dynamic library 'ext\pdo_sqlite' - 指定されたモジュールが見つかりません。
 in Unknown on line 0
PHP Warning:  PHP Startup: Unable to load dynamic library 'ext\sqlite3' - 指定されたモジュールが見つかりません。
 in Unknown on line 0
PHP Warning:  PHP Startup: Unable to load dynamic library 'ext\curl' - 指定されたモジュールが見つかりません。
 in Unknown on line 0
PHP 5.6.37 (cli) (built: Jul 19 2018 18:17:53)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

何やら PHP が Warning を発しているのは、PHP5.6本来の .ini ファイルと同時に PHP7.2の .ini ファイルも読み込んでしまっているせいです。

PS> php --ini
(中略)
Configuration File (php.ini) Path: C:\WINDOWS
Loaded Configuration File:         C:\Users\kagata\scoop\apps\php56\current\php.ini
Scan for additional .ini files in: C:\Users\kagata\scoop\apps\php\current\cli;C:\Users\kagata\scoop\apps\php\current\cli\conf.d;
Additional .ini files parsed:      C:\Users\kagata\scoop\apps\php\current\cli\php.ini,
C:\Users\kagata\scoop\apps\php\current\cli\conf.d\custom.ini,
C:\Users\kagata\scoop\apps\php\current\cli\conf.d\xdebug.ini

実は、先ほど PHP7.2をインストールした際に、ユーザー環境変数 PHP_INI_SCAN_DIR がセットされています。ここには PHP7.2が .ini ファイルを探すべきディレクトリのパスが格納されています。

PS> $env:PHP_INI_SCAN_DIR
C:\Users\kagata\scoop\apps\php\current\cli;C:\Users\kagata\scoop\apps\php\current\cli\conf.d;

この環境変数が PHP5.6に切り替えてもそのまま残っているので、余計な .ini ファイルを読み込んでしまう、というわけです。

仕方がないので、環境変数を手で書き換えることにしました。今回はとりあえず環境変数の値を空にすると、設定ファイルの優先順に従って正しい .ini ファイルを読み込んでくれました。

> $env:PHP_INI_SCAN_DIR=""
> php --ini
Configuration File (php.ini) Path: C:\WINDOWS
Loaded Configuration File:         C:\Users\kagata\scoop\apps\php56\current\php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed:      (none)
PS> php -v
PHP 5.6.37 (cli) (built: Jul 19 2018 18:17:53)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

PHP バージョンの切り替えは scoop reset コマンドで行います。

PS> scoop reset php
PS> > php -v
PHP 7.2.8 (cli) (built: Jul 18 2018 10:03:03) ( ZTS MSVC15 (Visual C++ 2017) x64 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Xdebug v2.6.1, Copyright (c) 2002-2018, by Derick Rethans

PHP7.2 に切り替えると、環境変数 PHP_INI_SCAN_DIR もリセットされます。PHP5.6に切り替える際には、再度環境変数を上書きしましょう。

PS> scoop reset php56
PS> $env:PHP_INI_SCAN_DIR=""
PS> php -v
PHP 5.6.37 (cli) (built: Jul 19 2018 18:17:53)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

ちなみに、PHP7.2 を有効化した際にセットされるユーザー環境変数は、 %UserProfile%\scoop\apps\php\curren\manifest.json で次のように定義されています。

    "env_set": {
        "PHP_INI_SCAN_DIR": "$dir\\cli;$dir\\cli\\conf.d;"
    },

これにならって、 %UserProfile%\scoop\apps\php56\curren\manifest.json にも次のように記述しておけば、切り替えのたびに環境変数を手で上書きしなくてよいのですが…。

    "env_set": {
        "PHP_INI_SCAN_DIR": ""
    },

この記述がないのが不具合なのか、意図された仕様なのか…。version バケットの GitHub リポジトリにプルリクエストを出せばいいのかな。

まとめと発展的な話題

以上で、Windows 環境で PHP7.2と PHP5.6を切り替えて併用できるようになりました。一部で妙な動きをするところがありましたが、基本的には将来有望なツールだと感じています。だんだんこなれてくるとよいですね。

以下、補足的なお話と、ちょっと高度な話題です。

PHP のパッチバージョンも切り替えたい

versions バケットに入っている PHP は、5.4以降のマイナーバージョンごとの最新版です。もしかすると、何かの調査でパッチバージョンも切り替えたい、なんてことがあるかもしれません。

そんなときは php バケットを使いましょう。windows.php.netmuseum.php.net で配布されている Windows 向けバイナリがあらかたインストールできます。versions バケットにないパッチバージョンが手に入るほか、5.3以前のマイナーバージョン、果ては PHP4系やPHP3系の一部バージョンまでそろっています。ほとんど趣味の世界ですね。

ただ、それぞれに対応した Xdebug パッケージは入っていないようです。(たとえ入っていたとしても)ふつうの開発用途には、やはり main や versions バケットのものを使うのがよいでしょう。

PHP 以外のバージョンも切り替えたい

Web アプリケーションを開発していると、PHP 以外にも複数バージョンを共存させたいものが出てきます。たとえばわたしの場合は、Node.js の切り替えに Nodist、Ruby の切り替えに Uru をそれぞれ使ってきました。

これらももちろん、Scoop で複数インストールしてバージョンを切り替えることができます。ただ、インストールしたいバージョンがバケットにあるとは限らないのがちょっとつらいところです。

たとえば Node.js なら、versions バケットに各メジャーバージョンがそろっています。しかし、Ruby は1.9しか見当たりません。いずれも、Nodist や Uru に比べると、対応されているバージョンには限りがあります。非対応のバージョンをインストールしたいときは、次に述べる方法を使うことになるでしょう。

あんなものやこんなものも Scoop でインストールしたい

インストールしたいものがあるけれど、 scoop search でパッケージが見当たらない…そんなときは、awesome-scoop をのぞいてみましょう。有志の作成したいろいろなバケットがここにリストされています。ただ、バケットの作成はあくまで有志によるものなので、一部はメンテナンスが行き届いておらず古いアプリケーションをインストールするものもあります。新しいバケットを使うときは、manifest ファイルの内容やメンテナンス状況を確認したほうがよいでしょう。

awesome-scoop にも所望のパッケージが見当たらなければ、自分で対応させてしまいましょう。JSON 形式の manifest ファイルを作成することで、好きなアプリケーションを Scoop 経由でインストールできます。自作の manifest ファイルをバケットにまとめて公開することだってできます。

  • このエントリーをはてなブックマークに追加

この記事を読んだ人にオススメ