Fast PHP version manager for macOS and Linux, written in Rust. Inspired by fnm.
phm manages PHP versions with per-shell switching and automatic version detection from .php-version files and composer.json. Switching is instant — it just repoints symlinks, no process restarts or shims.
brew tap Rovasch/phm
brew install phmDownload the binary for your architecture from the latest release:
| Platform | Binary |
|---|---|
| Linux x86_64 | phm-x86_64-unknown-linux-gnu.tar.gz |
| Linux ARM64 | phm-aarch64-unknown-linux-gnu.tar.gz |
| Termux (Android ARM64) | phm-aarch64-unknown-linux-musl.tar.gz |
curl -fsSL https://github.com/Rovasch/phm/releases/latest/download/phm-x86_64-unknown-linux-gnu.tar.gz \
| tar xz -C ~/.local/bincargo install phmgit clone https://github.com/Rovasch/phm.git
cd phm
cargo build --releaseRun phm shim create — this installs phm into your shell automatically:
phm shim createIt detects your current shell and writes to the appropriate config file:
| Shell | Config target | What gets written |
|---|---|---|
| Zsh | ~/.zshenv (or sourced custom file) |
Shim PATH + eval "$(phm env --shell zsh --use-on-cd)" |
| Bash | ~/.bashrc (or sourced custom file) |
Shim PATH + eval "$(phm env --shell bash --use-on-cd)" |
| Fish | ~/.config/fish/conf.d/phm.fish |
Shim PATH + phm env --shell fish --use-on-cd | source |
Then open a new terminal session, or reload your config:
# Zsh
source ~/.zshrc
# Bash
source ~/.bashrc
# Fish (restart terminal, or):
source ~/.config/fish/conf.d/phm.fishIf you prefer to configure manually, add to your shell config:
Zsh (~/.zshrc):
eval "$(phm env --shell zsh --use-on-cd)"If your prompt already shows the active PHP version, you can opt into a fully silent session:
eval "$(phm env --shell zsh --use-on-cd --silent)"Bash (~/.bashrc):
eval "$(phm env --shell bash --use-on-cd)"Fish (~/.config/fish/config.fish):
phm env --shell fish --use-on-cd | sourcephm uses Homebrew. Versions 8.x and up use the standard formula; 7.x taps shivammathur/php:
phm install 8.4
phm install 7.4 # taps shivammathur/php automatically
phm default 8.4phm downloads pre-built static PHP binaries (PHP 8.x) from static-php-cli:
phm install 8.3 # downloads ~7MB static binary, no sudo required
phm install 8.4
phm default 8.3PHP 7.x is not available as a managed install on Linux. Install it via your system package manager, and phm will discover and switch it automatically:
# Ubuntu/Debian
sudo apt install php7.4
# Arch (AUR)
yay -S php74
# Then phm sees it:
phm list
phm use 7.4To browse available versions:
phm list-remotepkg install php # or a specific version like php8.3
phm shim create # sets up shell integration
phm list # discovers the installed PHPWhen your shell starts, phm env creates a per-shell directory with symlinks pointing to your active PHP version's binaries:
~/.local/state/phm/multishells/<shell-id>/bin/
php -> /path/to/php@8.4/bin/php
phpize -> /path/to/php@8.4/bin/phpize
...
This directory is prepended to your PATH. Switching versions just repoints the symlinks — no process restarts, no global state changes.
Each terminal session gets its own symlink directory. Running phm use 8.2 in one terminal does not affect other terminals. Work on two projects requiring different PHP versions simultaneously.
With --use-on-cd, phm hooks into your shell's directory change event. When you cd into a directory containing composer.json or .php-version, phm switches automatically.
Version files checked:
.php-version— plain text file containing the version (e.g.,8.2). Takes priority.composer.json— reads therequire.phpconstraint and resolves to the lowest matching installed version.
The search walks up parent directories, so a .php-version at the repo root covers all subdirectories.
Constraint examples:
| composer.json require | Resolved version |
|---|---|
>=8.2 |
8.2 |
^8.2 |
8.2 |
~8.2 |
8.2 |
^7.4 || ^8.0 |
8.0 |
8.2.* |
8.2 |
When the version doesn't change between directories, phm exits silently with no overhead.
Switch the current shell to a specific PHP version. Without a version argument, auto-detects from .php-version or composer.json.
phm use 8.2 # Switch to PHP 8.2
phm use # Auto-detect from project files
phm use --silent 8.2 # Suppress success output for this invocationSet or show the default PHP version used for new shells.
phm default 8.4 # Set default
phm default # Show current defaultList all installed PHP versions. Marks the current and default versions.
$ phm list
7.4
* 8.2 (current)
8.4 (default)
8.5
List PHP versions available to download and install.
$ phm list-remote
8.0
8.1
8.2
* 8.3 (installed)
8.4
Install a PHP version.
- macOS: uses Homebrew
- Linux: downloads a static binary from static-php-cli (PHP 8.x only)
phm install 8.3
phm install 7.4 # macOS: taps shivammathur/php
# Linux: prints package manager hintUninstall a phm-managed PHP version. Prevents uninstalling the default version. On Linux, system-installed PHP (e.g. from apt/pacman) must be removed via the system package manager.
phm uninstall 8.3Run a command with a specific PHP version without switching the shell.
phm exec 8.1 -- php -v
phm exec 8.1 -- composer installPrint the active PHP version.
Print the resolved path to the active php binary. Useful for IDE configuration.
Set up shims for non-interactive shells (IDEs, CI, scripts). Writes the shim PATH and eval line to your shell config automatically.
phm shim createDiagnose common issues: missing versions, stale state, PATH conflicts, composer availability.
$ phm doctor
✓ 3 PHP version(s) found: 7.4, 8.2, 8.5
✓ Default version: 8.5
✓ Shell integration active
✓ Composer found
✓ No stale multishell directories
All checks passed!
Generate shell completions.
# Zsh (add to .zshrc)
eval "$(phm completions zsh)"
# Bash (macOS/Homebrew)
phm completions bash > "$(brew --prefix)/etc/bash_completion.d/phm"
# Bash (Linux)
phm completions bash > ~/.local/share/bash-completion/completions/phm
# Fish
phm completions fish > ~/.config/fish/completions/phm.fish| phm | Herd | brew-php-switcher | |
|---|---|---|---|
| Switch speed | ~1ms (symlink swap) | ~100ms | ~2s (brew link/unlink) |
| Per-shell versions | Yes | No (global) | No (global) |
| Auto-switch on cd | Yes | No | No |
| Multi-terminal | Yes | No | No |
| Linux support | Yes | No | No |
| Written in | Rust | PHP/Electron | Bash/Ruby |
- Apple Silicon or Intel
- Homebrew
- x86_64 or ARM64
- No root required for phm-managed versions (PHP 8.x)
- ARM64 Android device
- Use the
aarch64-unknown-linux-muslbinary