WindowsでPHP開発を続けながら、プロジェクトごとにPHPバージョンを安全に切り替えたい方向けの手順です。
PHP開発経験はあるが、WSL2やmiseの運用はこれから固めたい方を対象にしています。
ローカル開発環境の構築に絞って解説し、本番サーバー構築、Kubernetes、Dev Containersの全面運用は扱いません。
おすすめの構成は次の3点です。
- PHPバージョン管理:
mise - DB/Redis/Mailテスト環境:
Docker Compose - 作業場所: WSL2(
~/projects配下)
1. ゴールと結論
この記事で作る完成状態は次の3点です。
- 1台のWindows PCで
php@8.3/php@8.4/php@8.5を切り替えられる - プロジェクトごとに
.mise.tomlでバージョン固定できる - PostgreSQL / Redis / Mailpit を
docker compose up -dで起動できる
今回の運用ルールはシンプルです。
- PHPは
miseで使う - Dockerはミドルウェアだけに使う
この役割分担にすると、どのPHPで動かしているかを見失いにくくなります。
運用方針としては次を基準にすると進めやすいです。
- 新規開発の主軸: PHP 8.5
- 互換確認: PHP 8.4 / 8.3
2. 全体構成と役割分担
構成は次のとおりです。
Windows 11
└─ WSL2 (Ubuntu 24.04)
├─ mise
│ ├─ php@8.3
│ ├─ php@8.4
│ └─ php@8.5
└─ Docker Compose
├─ postgres
├─ redis
└─ mailpit
役割を表にすると次のようになります。
| コンポーネント | 役割 | どこで操作するか |
|---|---|---|
mise | PHPバージョン管理(Composerは同じWSL環境で実行) | WSLターミナル |
docker compose | PostgreSQL/Redis/Mailpit起動 | WSLターミナル |
| VS Code Remote-WSL | 編集と実行の統一 | Windows側VS Code + WSL接続 |
本記事では標準DBをPostgreSQLにしています。
プロジェクトは /mnt/c/... ではなく ~/projects/... に置きます。
WSL内でLinuxコマンドを使う場合、~/projects 配下の方が体感速度と安定性が高くなります。
3. 前提条件と事前チェック
Docker Desktopがインストール済みであることを前提とします。未導入の場合はDocker Desktop公式手順で導入してください。
WSLで docker compose を使うには、Docker Desktopの Settings > Resources > WSL Integration で Ubuntu-24.04 を有効化しておきます。
エディタは任意ですが、VS Codeを使う場合は Remote-WSL 拡張を入れておくと作業を統一しやすくなります。
PowerShell(管理者)で確認します。
wsl --status
wsl --list --verbose
docker version
確認ポイント:
wsl --list --verboseの対象ディストリビューションがVERSION 2- Docker Desktopが起動していて
docker versionが通る - タスクマネージャー > パフォーマンス > CPU で「仮想化: 有効」になっている
WSLが未導入なら次章のコマンドから始めてください。 Ubuntu 24.04がすでに起動できる状態なら、第4章は読み飛ばして第5章へ進んでください。
4. WSL2 + Ubuntu 24.04 のセットアップ
PowerShell(管理者)で実行します。
# Windows 11では既定でWSL2ですが、念のため明示
wsl --set-default-version 2
wsl --install -d Ubuntu-24.04
インストール後はWindowsを再起動します。再起動後、Ubuntuを初回起動してユーザー作成を済ませます。
以降はUbuntu(WSL)ターミナルで作業します。
sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential curl git unzip
mkdir -p ~/projects
cd ~/projects
この時点で、今後の作業ディレクトリを ~/projects に統一しておきます。
5. mise導入とPHP複数バージョン構築
5-1. miseをインストールする
スクリプト内容を確認したい場合は、先に curl https://mise.run で中身を確認してから実行してください。
curl https://mise.run | sh
bashで実行します:
echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc
source ~/.bashrc
確認:
mise --version
mise doctor
5-2. PHPビルド依存パッケージを入れる
Ubuntu 24.04では、先に次の依存パッケージを入れておきます。
sudo apt update
sudo apt install -y \
plocate pkg-config build-essential autoconf bison re2c \
libxml2-dev libssl-dev libsqlite3-dev libcurl4-openssl-dev \
libonig-dev libzip-dev libreadline-dev libicu-dev libpq-dev \
libjpeg-dev libpng-dev libfreetype6-dev libgd-dev
sudo updatedb
sudo updatedb は初回のみ数分かかる場合があります。完了してから次へ進みます。
5-3. PHP 8.3 / 8.4 / 8.5 をインストールする
初回インストールはソースビルドになるため、環境によっては数分から十数分かかります。
失敗した場合は詳細ログを出して原因を確認します。
mise install php@8.3
mise install php@8.4
mise install php@8.5
失敗時のみ、詳細ログ付きで再実行します。
mise install --verbose php@8.5
グローバル既定を設定:
mise use --global php@8.5
php --version
mise list php
5-4. Composerを確認する
まずは composer が使えるか確認します。
composer --version
composer: command not found の場合は、mise のシムを更新して再確認します。
mise reshim
composer --version
それでも見つからない場合は、Composer を手動導入します。
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
sudo mv composer.phar /usr/local/bin/composer
rm composer-setup.php
composer --version
6. プロジェクト単位のバージョン固定(.mise.toml)
3つのサンプルプロジェクトを作って切替を確認します。
mkdir -p ~/projects/php83-app ~/projects/php84-app ~/projects/php85-app
cd ~/projects/php83-app
mise use php@8.3
php --version
cd ~/projects/php84-app
mise use php@8.4
php --version
cd ~/projects/php85-app
mise use php@8.5
php --version
mise use を実行すると、各ディレクトリに .mise.toml が作られます。
例:
[tools]
php = "8.3"
.mise.toml はプロジェクトの再現性に関わるため、Gitを使っている場合はリポジトリに含めておくのがおすすめです。
(Gitの初期設定がまだなら、この手順は後回しで大丈夫です。)
例: ~/projects/php83-app をGit管理している場合
cd ~/projects/php83-app
git add .mise.toml
git commit -m "chore: pin php version with mise"
.mise.toml を置いたディレクトリの外で composer を実行すると、意図したPHPバージョンではなくグローバル設定で動作する場合があります。composer は必ず対象プロジェクト配下で実行してください。
7. Docker Composeでミドルウェアを用意する
ここではPostgreSQL/Redis/Mailpitを起動します。PHPコンテナは作りません。
mkdir -p ~/projects/php-infra
cd ~/projects/php-infra
~/projects/php-infra/compose.yml:
services:
postgres:
image: postgres:17-alpine
container_name: php-dev-postgres
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: app
TZ: Asia/Tokyo
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 10s
timeout: 5s
retries: 10
redis:
image: redis:7.4-alpine # 執筆時点の例。最新タグはDocker Hubで確認
container_name: php-dev-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 10
mailpit:
image: axllent/mailpit:latest # 執筆時点の例。最新タグはDocker Hubで確認
container_name: php-dev-mailpit
ports:
- "1025:1025"
- "8025:8025"
volumes:
postgres_data:
redis_data:
~/projects/php-infra/.env.example:
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=app
DB_USERNAME=app
DB_PASSWORD=app
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
MAIL_HOST=127.0.0.1
MAIL_PORT=1025
.env.example を .env にコピーして使います。
cp .env.example .env
起動・停止:
cd ~/projects/php-infra
docker compose up -d
docker compose ps
docker compose down
データを含めて初期化する場合:
docker compose down -v
8. 動作確認シナリオ
8-1. PHP切替の確認
cd ~/projects/php83-app && php --version
cd ~/projects/php84-app && php --version
cd ~/projects/php85-app && php --version
8.3.x / 8.4.x / 8.5.x がそれぞれ表示されればOKです。
8-2. PostgreSQLの確認
cd ~/projects/php-infra
docker compose exec postgres psql -U app -d app -c "SELECT version();"
バージョン文字列が返れば接続成功です。
8-3. Redisの確認
docker compose exec redis redis-cli ping
PONG が返ればOKです。
8-4. Mailpitの確認
ブラウザで http://localhost:8025 を開き、UIが表示されればOKです。
8-5. 失敗例と復旧(mise activate 未反映)
症状:
mise use php@8.3を実行したのにphp --versionが変わらない
確認:
mise doctor
which php
echo $PATH | tr ':' '\n' | grep mise
復旧:
source ~/.bashrc
8-6. 失敗例と復旧(gdlib / locate)
症状:
Package requirements (gdlib >= 2.1.0) were not metlocate: command not found
対処:
sudo apt update
sudo apt install -y plocate libgd-dev pkg-config
sudo updatedb
その後、mise install php@8.x を再実行します。
9. 日常運用ルール(更新・保守)
運用では、更新方針を先に決めておくと事故が減ります。
- パッチ更新(例: 8.5.x)は定期的に適用
- マイナー更新(8.4 -> 8.5)は案件ごとに計画移行
更新コマンド例:
# mise本体
mise self-update
# 利用中ツールの更新確認
mise outdated
# PHPの再取得(指定系列の最新パッチを取得)
mise install php@8.5
# Dockerイメージ更新
cd ~/projects/php-infra
docker compose pull
docker compose up -d
切り分けは次の順で行うと早いです。
php --versionとmise current phpmise doctordocker compose ps- ポート競合(5432/6379/8025)確認
10. よくある詰まりどころ
mise で切り替わらない
- 原因:
mise activateがシェルに未設定 - 対応: シェル設定追記 ->
source ~/.bashrc->mise doctor
/mnt/c 配下で動作が重い
- 原因: WSL上のI/O特性
- 対応:
~/projects配下へ移動
mise install php@... が失敗する
- 原因: ビルド依存不足
- 対応: 5章の依存パッケージを追加し、
mise install --verbose php@8.5でログを確認して再実行
composer が見つからない
- 原因:
miseのシム未更新、またはComposer未導入 - 対応: まず
mise reshimとcomposer --versionで確認し、見つからなければ5章の手順でComposerを手動導入
docker compose up でポート競合
- 原因: 既存プロセスが同じポートを使用
- 対応:
compose.ymlのホスト側ポートを変更(例:5433:5432)
WSLで docker compose が動かない
- 原因: Docker DesktopのWSL Integrationが無効
- 対応:
Settings > Resources > WSL IntegrationでUbuntu-24.04を有効化し、Docker Desktopを再起動
WSLターミナルとPowerShellを混在させてしまう
- 原因: 実行コンテキスト混在
- 対応: PHP/Composer/mise/docker compose の日常操作はWSLターミナルに統一
まとめ
WindowsでPHPを複数バージョン運用するなら、WSL2 + mise + Docker Compose は手順の再現性と運用のしやすさを両立しやすい構成です。
「PHPはmise、ミドルウェアはDocker」という役割分離を守ることで、どのPHPで動かしているかを見失いにくくなります。
この構成を土台にすれば、案件ごとに .mise.toml だけでPHPバージョンを安全に固定できます。