Keeping PHP updated and happy

By Erik, Sun, 10/16/2016 - 18:08

Homebrew is how I tend to manage all of my local packages. It works great for me and gives me the flexibility of installing my own packages without the complexity and overhead of a system like Boxen which I used for a couple of years and had a great love/hate relationship trying to learn all about it. But it turned out in the long run to be just a bit too much effort for the return.

Installing PHP

It is very easy to install multiple versions of php simultaneously. You can simply run:

$ brew taps homebrew/homebrew-php
$ brew install php56

where php56, can be any valid php version that is available:

$ brew search /php\\d\\d$/

Using phpenv

The issue with this system is that by itself, brew tends to want the php binary being installed to be linked to /usr/local/bin/php. Many suggestions have you swap out which php binary is symlinked to /usr/local/bin/php but that is always fraught with peril since you then need to remember which version is current in each project.

I work on a number of different PHP based projects, mostly Drupal or Symfony. So this is where I turned to a project called phpenv. phpenv is based on a similar project for Ruby named rbenv.

$ brew install phpenv

The upshot is that instead of running PHP out of a normal location like /usr/local/bin, instead, we link php to the phpenv "shim" which is a wrapper. The wrapper checks for a file named .php-version starting in the current directory and working its way up through parent directories. If it can't find one, it checks for a global variable set in ~/.phpenv/version which can be set with:

$ phpenv global 5.6

You can set local versions simply by swapping the "global" modifier with "local".

$ phpenv local 5.6

Since phpenv was built to install new versions of php directly, we needed to adapt it to using brew installed versions of php. Normally, phpenv would have a list of possible versions in the ~/.phpenv/versions/ directory. So instead of building them there, we simply create symlinks to where brew has installed versions of php.

$ ls -l ~/.phpenv/versions/
total 48
lrwxr-xr-x  1 eporama  staff  32 Oct 14 16:24 5.6 -> /usr/local/Cellar/php56/5.6.26_3
lrwxr-xr-x  1 eporama  staff  32 Oct 14 16:24 7.0 -> /usr/local/Cellar/php70/7.0.11_5
lrwxr-xr-x  1 eporama  staff  36 Oct 14 16:24 7.1 -> /usr/local/Cellar/php71/7.1.0-rc.3_8

Keeping php versions updated

To keep these up to date, simply running brew upgrade doesn't work since brew doesn't like to update or install any new version of php when there is a different version already linked. Since Brew is unaware that we're going to use phpenv, it is assuming that you want to link /usr/local/bin/php to the version of php that you are installing, so if you install a different version, it will complain if the previous version is still linked. Luckily, it's fairly straight forward to link and unlink the binaries that are provided by any brew project. For example, if you currently had php-5.6 installed and linked, but wanted to update php-7.0, you would need to unlink php-5.6, then update and reverse the linking afterward.

$ brew unlink php56
$ brew update php70
$ brew unlink php70
$ brew link php56

I don't need to do most of that because I always leave the php packages unlinked so that phpenv can handle them.

To wrap it all together

We wrap all of these together in a handy script that will update php via brew and remake all of the appropriate phpenv symlinks.