A simple PHP version manager
I have multiple versions of PHP installed with Homebrew on my computer and it has always been a nightmare to use a specific version in the terminal for different commands. For example, installing Composer dependencies with a specific PHP version:
/usr/bin/local/php73 $(which composer) installI ended up writing a small ZSH function to easily switch from one version to another à la nvm. It is quite simple under the hood as it simply changes the content of the $PATH variable so that the php command points to the desired version.
The function can be used as follows:
# Use a specific version
pvm use 7.4
# Use the system default version
pvm use system
# Try to guess a version from a `composer.json` file up in the folder tree
pvm use
# Display the current version
pvm current
# List available versions
pvm list
pvm lsThe pvm use command can be used without specifying a version, it will try to find a composer.json file up in the folder tree and guess a PHP version from its dependencies.
Disclaimer
This is a script created specificly to work on my local environment, I can not guarantee that it will work correctly on any other environment. Use it at your own risk.
The script
You will find the script below, to start using it, add it to your ~/.zshrc file or create a separate file and add the following to your ~/.zshrc:
source /path/to/pvm.zshYou also will need to have multiple versions of PHP installed with Homebrew as well as the jq CLI:
brew install jq \
    shivammathur/php/php \
    shivammathur/php/[email protected] \
    shivammathur/php/[email protected] \
    shivammathur/php/[email protected] \
    shivammathur/php/[email protected] \
    shivammathur/php/[email protected] \
    shivammathur/php/[email protected] \
    shivammathur/php/[email protected]Here is the script:
#!/bin/zsh
# Alias PHP version to Brew versions
function pvm() {
    zparseopts -D -E -a opts -verbose::=verbose v::=version -version::=version
    VERSION='0.0.2'
    brew_prefix=$(brew --prefix)
    function log() {
        if [[ $verbose ]]; then
            echo $1
        fi
    }
    function get_php_bin_path() {
        ls -d $brew_prefix/Cellar/php*/$1*/bin
    }
    function get_php_versions() {
        ls -d $brew_prefix/Cellar/php*/* | grep -E -o '/[0-9]+.[0-9]+' | sed -E 's#/##'
    }
    function set_php_version() {
        _current_php_version=$(pvm current)
        _current_path=$(get_php_bin_path "$_current_php_version")
        _old_path=$(php -r "echo str_replace('$_current_path:', '', '$PATH');")
        if [[ -z $1 ]]; then
            export PATH="$_old_path"
            return
        fi
        PHP_VERSIONS="$(get_php_versions)"
        _version_exists="$(php -r "echo preg_match('/^$1$/m', '$PHP_VERSIONS');")"
        if [[ $_version_exists == "0" ]]; then
            echo "Could not find PHP version $1, is it installed?";
            return
        fi
        _new_path=$(get_php_bin_path $1)
        _old_path=$(php -r "echo str_replace('$_new_path:', '', '$_old_path');")
        export PATH="$_new_path:$_old_path"
    }
    log "pvm@$VERSION"
    if [[ $1 == 'current' ]]; then
        local PHP_VERSION=$(php -v | grep -Eo 'PHP [0-9]+.[0-9]+')
        echo ${PHP_VERSION/PHP /};
        return;
    fi
    if [[ $1 == 'use' ]]; then
        if [[ $2 == 'system' ]]; then
            log 'use system'
            set_php_version
        elif [[ -n $2 ]]; then
            log "use $2"
            set_php_version $2
        else
            composerjson_path=$(_find_up composer.json | tr -d '[:space:]')
            if [[ -a $composerjson_path/composer.json ]]; then
                pvm_version=$(cat $composerjson_path/composer.json | jq '.require.php' | grep -Eo '[0-9](.[0-9])?' | head -n 1)
                log "use v$pvm_version from composer.json"
                if [[ -n $pvm_version ]]; then
                    set_php_version $pvm_version
                    return
                fi
            fi
        fi
        return
    fi
    if [[ $1 == 'list' || $1 == 'ls' ]]; then
        get_php_versions
        return
    fi
    if [[ $version == '--version' || $version == '-v' ]]; then
        echo $VERSION
        return
    fi;
    echo "pvm $VERSION
A fast and simple PHP manager
USAGE:
    pvm <SUBCOMMAND>
FLAGS:
    -h, --help
        Prints help information
    -v, --version
        Prints version information
SUBCOMMANDS:
    current       Print the current PHP version
    use [version] Change PHP version
    list          List all available PHP versions [alias: ls]
"
}