Automatically Switch PHP Version on cd

Written by - Blog - - Aggregated on Wednesday August 8, 2018

After using phpbrew to manage my local PHP versions for a while, I got tired of re-compiling PHP after every release and decided to install multiple PHP versions side-by-side with Ondřej Surý's PPA. One of the features I missed from phpbrew was the ability to run a command like phpbrew use php-7.2.8 to automatically change the php command to that version, so I ended up implementing this feature myself using symlinks and shell aliases.

Switching PHP Versions

By default, Ubunutu creates a symlink at /etc/alternative/php which points to an executable like /usr/bin/php5.6. I therefore wanted to create my own shell alias to change that symlink by simply running a command like php72

However, /etc/alternative/php is for the whole system, and I'd have to use sudo everytime I wanted to change that symlink (or change permissions in /etc/alternative). But, since I'm the only user on my laptop, I instead hard-coded a symlink from /etc/alternative/php to another symlink in my home directory:

Now my aliases can simply update that /home/codell/.php symlink without needing sudo! Here's the full list of aliases which I dropped inside of my ~/.zshrc file:

alias php56="ln -sf /usr/bin/php5.6 /home/codell/.php && php -v"
alias php70="ln -sf /usr/bin/php7.0 /home/codell/.php && php -v"
alias php71="ln -sf /usr/bin/php7.1 /home/codell/.php && php -v"
alias php72="ln -sf /usr/bin/php7.2 /home/codell/.php && php -v"

Now I can simply run php7.2 or any other version number to make php alias to that specific version!

(This approach also works perfectly fine if you use bash instead of zsh - just drop your aliases into ~/.bashrc instead.)

Automating This Based on composer.json

But let's take this one step further - most of the projects I work on have a PHP constraint in their composer.json file:

    "name": "some/project",
    "require": {
        "php": ">=7.1"

It would be awesome if my shell could automatically switch PHP versions for me based on what that project uses - so that's exactly what I implemented for zsh!

autoload -U add-zsh-hook
change-php-version() {
  if [ -f composer.json ]; then
    PHPVERSION=$(cat composer.json | jq '.require.php' | grep -o '[0-9].[0-9]')
    if [ ! -z "$PHPVERSION" ] && [ -e "/usr/bin/php$PHPVERSION" ]; then
      ln -sf "/usr/bin/php$PHPVERSION" /home/codell/.php
      php -v | head -n 1 | awk '{print $1 " " $2}'

add-zsh-hook chpwd change-php-version

I simply dropped that into my ~/.zshrc file. Now, whenever I cd into a different project directory, zsh checks my composer.json and switches to that PHP version automatically! It also outputs which version it switched to:

It's not perfect though, as it doesn't actually parse the constraint - it does a dumb regex match and assumes whatever x.y version it sees is what you want. If your constraint was something like >7.0 it would think you wanted 7.0! However, none of my projects have constraints like that, so I'm not too concerned. Perhaps in the future I'll make this smarter.

« Security Release: Laravel v5.6.30 and … - Laravel News

Laracasts - More Sensible Achievement Defaults »