PVM (PHP Version Manager) is a lightweight PowerShell tool for Windows that makes it easy to install, switch, and manage multiple PHP versions.
- Features
- Requirements
- Installation & Setup
- Quick Start
- Usage
- Data Storage
- Running Tests
- Contributing
- Credits
- License
- Install and manage multiple PHP versions
- Automatic PHP version detection
- Manage php.ini settings and extensions
- Create, save, and reuse PHP configuration profiles
- Built-in cache management
- Intelligent command suggestions
- Automatic update checking and self-update support
- Built-in test runner with coverage support
- Reusable project scripts similar to npm or Composer scripts
- Responsive long-running operations with progress indicators
- Optional sound notifications for test results
- Windows 10 or Windows 11
- PowerShell 5.1+ or PowerShell 7+
- Internet connection for installing PHP versions and extensions
Clone the repository, copy the environment file, run setup, and ensure the project directory is available in your PATH.
git clone https://github.com/drissboumlik/pvm
cd pvm
cp .env.example .env # edit .env to set your config values before running setup
# Run this command to setup pvm
pvm setup
# Recreate missing directories, templates and configuration files & Fix the .env file
pvm repairEnvironment Configuration:
The .env file lets you customize how PVM behaves. Key configuration options include:
SOUNDS_DISABLED- Disable sound notifications (default: false)CACHE_MAX_HOURS- Cached available versions expiration in hours (default: 168)ENABLE_UPDATE_CHECK- Enable automatic update checks (default: true)UPDATE_CHECK_INTERVAL_HOURS- Update check interval in hours (default: 24)DEFAULT_LOG_PAGE_SIZE- Default page size for log display (default: 5)
See .env.example for the complete list of configuration options.
The commands below install PHP 8.4, switch to it, and verify the active version.
# Install PHP 8.4
pvm install 8.4
# Switch to PHP 8.4
pvm use 8.4
# Verify active version
pvm current
# List installed versions
pvm list# Display the available options
pvm help
# Display help for a specific command
pvm help <command>
# Example: pvm help setup
# PVM suggests the closest matching command if you mistype one
# Example: pvm intsall 8.4 β did you mean: install?
# Displays information about the environment including PVM version, currently active PHP version, paths, and environment variables.
pvm info [--verbose]
# Display the current PVM version
pvm version
# Display active PHP version
pvm current
# List installed PHP versions
pvm list # pvm ls
# List installed versions with 8.2 in the name
pvm list --search=<version>
# Example: pvm list --search=8.2
# List installed versions matching x86 and nts
pvm list [x86|x64] [ts|nts]
# Example: pvm list x86 nts
# List installable PHP versions from remote source
pvm list available # pvm ls available
# List installable PHP versions from remote source matching x86 and nts
pvm list available [x86|x64] [ts|nts]
# Example: pvm list available x86 nts
# List available versions with 8.2 in the name
pvm list available --search=<version>
# Example: pvm list available --search=8.2
# Install a specific version.
pvm install <version> # pvm i <version>
# Example: pvm install 8.4 # pvm i 8.4
# Install a specific version for a specific arch & build type
pvm install <version> [x86|x64] [ts|nts]
# Example: pvm install 8.4 x64 nts # pvm i 8.4 x64 nts
# Install the latest available PHP version.
pvm install latest # pvm i latest
# Uninstall a specific version
pvm uninstall <version> [--yes|-y] # pvm rm <version> [--yes|-y]
# Example: pvm uninstall 8.4 # pvm rm 8.4
# Example: pvm uninstall 8.4 -y # pvm rm 8.4 -y # Skip confirmation
# Switch to use the specified version
pvm use <version>
# Example: pvm use 8.4
# Update PVM to the latest version from the repository
pvm update [--check]
# Example: pvm update
# Example: pvm update --checkPVM can detect the PHP version from:
.php-versioncomposer.json
Example .php-version:
8.4
Example composer.json:
{
"require": {
"php": "^8.4"
}
}# Install the PHP version specified by your project.
pvm install auto # pvm i auto
# Switch to use the detected PHP version from .php-version or composer.json in your current project/directory
pvm use auto# Check status of multiple extensions
pvm ini status <extension> # It shows all matching extensions
# Example: pvm ini status xdebug opcache
# Example: pvm ini status sql
# Enable or disable multiple extensions
pvm ini enable <extension> # It shows all matching extensions then enables the selected one
# Example: pvm ini enable xdebug opcache
# Example: pvm ini enable sql
pvm ini disable <extension> # It shows all matching extensions then disables the selected one
# Example: pvm ini disable xdebug opcache
# Example: pvm ini disable sql
# Set or Get multiple settings values and change the status
pvm ini set <setting>=<value> [--disable] # Default is enabling the setting
pvm ini set <setting> [--disable] # It shows all matching settings then enables the selected one
# Example: pvm ini set memory_limit=512M max_file_uploads=20
# Example: pvm ini set max_input_time=60 --disable
# Example: pvm ini set memory=1G
# Example: pvm ini set memory
pvm ini get <setting> # It shows all matching settings
# Example: pvm ini get memory_limit max_file_uploads
# Example: pvm ini get memory
# Install extensions from remote source
pvm ini add <extension> [--yes|-y] # It shows all matching extensions then adds the selected one
# Example: pvm ini add opcache
# Example: pvm ini add opcache -y # Skip confirmation
# Remove extensions from extensions directory and ini file
pvm ini remove <extension> [--yes|-y] # It shows all matching extensions then removes the selected one
# Example: pvm ini remove opcache
# Example: pvm ini remove opcache -y # Skip confirmation
# List installed extensions
pvm ini ext
# List available extensions from remote source
pvm ini ext available
# List installed extensions with 'zip' in their name
pvm ini ext --search=<extension>
# Example: pvm ini ext --search=zip
# List available extensions with 'zip' in their name
pvm ini ext available --search=<extension>
# Example: pvm ini ext available --search=zip
# Restore backup
pvm ini restore # PVM automatically creates php.ini backups before modifying settings or extensions.
# Display information about the current PHP (version, path, extensions, settings)
pvm ini info
# Display information about the current PHP extensions
pvm ini info extensions
# Display information about the current PHP settings
pvm ini info settings
# Display information about the current PHP (version, path, extensions, settings) with 'cache' in their name
pvm ini info --search=<term>
# Example: pvm ini info --search=cachepvm log # Default value for pagination is 5
pvm log --pageSize=<number>
# Example: pvm log --pageSize=3
pvm log --search=<term>
# Example: pvm log --search=errorSave, load, and share PHP settings and extensions using JSON profiles:
# Save current PHP configuration to a profile
pvm profile save <name> [description]
# Example: pvm profile save development
# Example: pvm profile save production "Production configuration"
# Load and apply a saved profile
pvm profile load <name>
# Example: pvm profile load development
# List all available profiles
pvm profile list
# Show detailed profile contents
pvm profile show <name>
# Example: pvm profile show development
# Delete a profile
pvm profile delete <name> [--yes|-y]
# Example: pvm profile delete old-profile
# Example: pvm profile delete old-profile -y # Skip confirmation
# Remove all profiles files
pvm profile clear [--yes|-y]
# Example: pvm profile clear -y # Skip confirmation
# Export profile to a JSON file
pvm profile export <name> <path>
# Example: pvm profile export development
# Example: pvm profile export dev ./backup.json
# Import profile from a JSON file
pvm profile import <path> <name>
# Example: pvm profile import ./my-profile.json
# Example: pvm profile import ./profile.json custom-nameProfile Structure: Profiles are stored as JSON files in storage/data/profiles/ and contain:
- Popular/common PHP settings (key-value pairs with enabled/disabled state)
- Popular/common extensions (enabled/disabled state and type)
- Metadata (name, description, creation date, PHP version)
Note: Only popular/common settings and extensions are saved in profiles. This keeps profiles focused and manageable.
Manage the cache directory and its contents:
# List files in the cache directory
pvm cache list
# Show details of a specific cache file
pvm cache show <name>
# Example: pvm cache show example-cache
# Remove a specific cache file
pvm cache delete <name> [--yes|-y]
# Example: pvm cache delete example-cache
# Example: pvm cache delete example-cache -y # Skip confirmation
# Remove all cache files
pvm cache clear [--yes|-y]
# Example: pvm cache clear -y # Skip confirmationLong-running operations β listing available PHP versions, fetching extensions, running multi-config test scripts β execute as background jobs with a spinner shown in the terminal, so the CLI stays responsive.
PVM can play optional notification sounds when long-running commands complete or fail.
Configure the feature in .env:
# Enable sound notifications (default)
SOUNDS_DISABLED=false
# Disable sound notifications
SOUNDS_DISABLED=trueSound Feedback Features:
- Success sounds play after successful command completion
- Error sounds play when commands fail
- Test completion sounds play after running tests
- Sounds are automatically disabled in subprocess mode
You can use the following aliases for commonly used commands.
To view the complete list from the CLI:
pvm aliases| Alias | Command |
|---|---|
| ? | help |
| h | help |
| ver | version |
| init | setup |
| cur | current |
| active | current |
| ls | list |
| i | install |
| u | uninstall |
| switch | use |
| on | enable |
| off | disable |
| a | add |
| + | add |
| rm | remove |
| - | remove |
| del | delete |
| cls | clear |
| logs | log |
| upgrade | update |
| fix | repair |
Customizing Aliases:
You can customize aliases by editing the storage/data/templates/aliases.json file.
| Option | Meaning |
|---|---|
| x86 | 32-bit |
| x64 | 64-bit |
| ts | Thread Safe |
| nts | Non Thread Safe |
The following command groups support both syntaxes:
pvm help <subcommand>
pvm help:<subcommand>
pvm ini <subcommand>
pvm ini:<subcommand>
pvm profile <subcommand>
pvm profile:<subcommand>
pvm cache <subcommand>
pvm cache:<subcommand>| Item | Location |
|---|---|
| PHP Versions | storage/php/ |
| Templates | storage/data/templates |
| Profiles | storage/data/profiles/ |
| Cache | storage/data/cache/ |
| Logs | storage/logs/ |
| Assets | storage/assets/ |
Note: The storage/data/templates/ directory contains aliases.json and scripts.json for customizing command aliases and test scripts.
Run tests against the PowerShell scripts in the repo β especially useful for contributors verifying changes before submitting a pull request:
To run the test suite, install the Pester testing framework.
Open PowerShell as Administrator and run:
Install-Module -Name Pester -Force -SkipPublisherCheckπ‘ If prompted to trust the repository, type Y and press Enter.
You can verify the installation with:
Get-Module -ListAvailable PesterBy default, pvm test auto-detects pwsh if available, falling back to powershell. Use --shell=powershell or --shell=pwsh to force a specific engine β useful for verifying PS 5.1/7 cross-version compatibility.
pvm test <files> [--exclude=<files>] [--coverage[=<number>]] [--verbosity=<verbosity>] [--tag=<tag>] [--sort=<sort>] [--group=<group>] [--shell=<shell>] [--pester=<version>] [--mute]
# Examples:
pvm test # .............................. Runs all tests with Normal (default) verbosity.
pvm test use install # .................. Runs only 'use.tests.ps1' and 'install.tests.ps1' files with Normal verbosity.
pvm test --exclude=use,install # ........ Runs all tests except 'use.tests.ps1' and 'install.tests.ps1' with Normal verbosity.
pvm test --verbosity=Detailed # ......... Runs all tests with Detailed verbosity.
pvm test --coverage # ................... Runs all tests and generates coverage report (target: 75%)
pvm test --coverage=80.5 # .............. Runs all tests and generates coverage report (target: 80.5%)
pvm test --sort=duration # .............. Runs all tests and sorts results by duration (ascending)
pvm test --sort=-duration # ............. Runs all tests and sorts results by duration (descending)
pvm test --sort=file # .................. Runs all tests and sorts results by file name.
pvm test --tag=myTag #................... Runs only runs tests with tag "myTag".
pvm test --group=folder # ............... Runs all tests and groups results by folder.
pvm test --group=coverage # ............. Runs all tests and groups results by coverage band.
pvm test --shell=powershell # ........... Forces Windows PowerShell (powershell.exe) instead of auto-detected pwsh.
pvm test --shell=pwsh # ................. Forces PowerShell 7+ (pwsh.exe).
pvm test --pester=5.7.0 # ............... Forces Pester 5.7.0.
pvm test --mute #........................ Runs tests and forces mute mode (SOUNDS_DISABLED = false)PVM includes reusable scripts, similar to Composer or npm scripts, allowing frequently used test commands to be executed with a short alias.
The test runner provides visual feedback with spinner animations during execution and sound notifications upon completion (see Sound Notifications for configuration).
# Run a specific script
pvm run <script-name> [--mute] <files>
# List all available predefined scripts
pvm run list
# Examples:
pvm run test:quiet # ................ Runs tests with verbosity set to None
pvm run test:cov80 # ................ Runs tests with 80% coverage target
pvm run test:cov90 # ................ Runs tests with 90% coverage target
pvm run test:duration # ............. Runs tests with duration descending sort
pvm run test:verbose # .............. Runs tests with coverage and detailed output
pvm run test:shell # ................ Runs tests with Windows PowerShell and PowerShell Core
pvm run test:pester # ............... Runs tests with Pester 5.7.1 and 6.0.0
pvm run test:matrix # ............... Runs tests with all supported PowerShell versions and Pester versions
pvm run test:matrix --mute # ........ Runs tests and forces mute mode (SOUNDS_DISABLED = false)'
pvm run test:matrix use install # ... Runs only 'use.tests.ps1' and 'install.tests.ps1' with all supported PowerShell versions and Pester versionsAvailable Scripts:
| Script Name | Command | Description |
|---|---|---|
test:quiet |
pvm test --coverage=85 --sort=coverage --group=folder --verbosity=None |
Runs tests with verbosity set to None |
test:cov80 |
pvm test --coverage=80 --sort=coverage --group=folder --verbosity=None |
Runs tests with 80% coverage target |
test:cov90 |
pvm test --coverage=90 --sort=coverage --group=folder --verbosity=None |
Runs tests with 90% coverage target |
test:duration |
pvm test --sort=-duration --group=folder --verbosity=None |
Runs tests with duration descending sort |
test:verbose |
pvm test --coverage=85 --sort=coverage --group=folder --verbosity=Detailed |
Runs tests with coverage and detailed output |
test:shell |
pvm test --coverage=85 --verbosity=None --sort=coverage --group=folder --shell=powershell and --shell=pwsh |
Runs tests with both pwsh and powershell |
test:pester |
pvm test --coverage=85 --verbosity=None --sort=coverage --group=folder --pester=5.7.1 and --pester=6.0.0 |
Runs tests with Pester 5.7 and 6.0 |
test:matrix |
pvm test --coverage=85 --verbosity=None --sort=coverage --group=folder --shell=powershell --pester=5.7.1, pvm test --coverage=85 --verbosity=None --sort=coverage --group=folder --shell=pwsh --pester=5.7.1, and pvm test --coverage=85 --verbosity=None --sort=coverage --group=folder --shell=pwsh --pester=6.0.0 |
Runs the predefined shell/Pester matrix combinations |
Customizing Scripts:
You can customize scripts by editing the storage/data/templates/scripts.json file, Add or modify scripts to suit your workflow.
Please see CONTRIBUTING for details.
The MIT License (MIT). Please see License File for more information.