How to Use PHPbrew and VirtPHP
We’ve all been in the situation where we have one version installed. Maybe that version is whatever came installed on our operating system. Maybe it is a version bundled into MAMP/WAMP/XAMPP.
How do you go about switching that PHP version?
How do you switch to one version, then switch back again?
How do you go about switching that version of PHP, but only for one single application on your computer?
The Ruby and Python communities have had tools for dealing with this for years. PHP has them now too, but there was nowhere near enough fanfare.
PHPbrew is an amazing little tool which has been out since 2012.
It builds and installs PHP versions, and places them into a folder in your home directory. This means you can manage your own versions of PHP. PHPbrew will build various versions, place them in the home folder, and let you switch between them whenever you want.
It should be worth noting that PHPbrew has a fair few requirements, but they are not tough to install. I did not have to install anything, as after using this Macbook for over two years I had all the requirements anyway.
If you are a Mac OS X user – and I will continue to assume that you are – then you can use Homebrew (no relation) to install dependencies.
brew install automake autoconf curl pcre re2c mhash libtool icu4c gettext jpeg libxml2 mcrypt gmp libevent brew link icu4c
Then you will need to install PHPbrew itself:
curl -L -O https://github.com/phpbrew/phpbrew/raw/master/phpbrew chmod +x phpbrew sudo mv phpbrew /usr/bin/phpbrew
This downloads PHPbrew, adds the “executable” permission and moves it to
Hop over to their basic usage instructions to see how to get things initialized in more detail, but the basics should just be:
With phpbrew initialised you will need to add these lines to your
echo "source $HOME/.phpbrew/bashrc" >> ~/.bashrc
If you are using a non-default shell like ZSH then you will need to edit your
.zshrc file instead.
Installing PHP using PHPbrew
Before we can install a version of PHP, we need to see which versions are available to PHPbrew. We can do this with a simple command:
phpbrew known Available stable versions: 5.6+ 5.6.0 5.5+ 5.5.17, 5.5.16, 5.5.15, 5.5.14, 5.5.13, 5.5.12, 5.5.11, 5.5.10 5.4+ 5.4.33, 5.4.32, 5.4.31, 5.4.30, 5.4.29, 5.4.28, 5.4.27, 5.4.26 5.3+ 5.3.29, 5.3.28, 5.3.27, 5.3.26, 5.3.25, 5.3.24, 5.3.23, 5.3.22
At the time of writing, PHP 5.6.0 is the latest version, and versions of PHP before 5.3 are not supported.
We want to install PHP 5.6.0, so we can use all the great new features, so lets ask phpbrew to do that:
phpbrew install 5.6.0
Note that if you are using PHPbrew 1.14 or earlier then this would fail on some systems with an error about not having XML enabled. When XML is missing, PHPbrew will fail to install something called PEAR and the build will break. We can get around that using the
phpbrew install 5.6.0 +xml_all
+xml_all option is what PHPbrew calls “Variants”, and there are a lot more available.
When installing PHP yourself, there are lots of options to enable or disable features. PHPbrew simplifies this and abstracts it, using a feature called Variants.
Things like database drivers, curl, the GD image library and JSON are all available as optional variants.
PHPbrew has one variant called “default”, which – contrary to expectation – is not used by default. Instead it acts as a shortcut for enabling the following variants:
default may contain more than you need, so a more granular approach may be more to your liking.
Lets say we just want to install PHP 5.6.0 to build a CLI application, that uses PDO to talk to a SQLite database. For that, we can do the following:
phpbrew install 5.6.0 +cli +pdo +sqlite +xml_all
This command will enable the PDO extension itself, and
sqlite enables the SQLite drivers. The
cli variant will install the command-line interface, and
xml_all will stop PHPbrew complaining about PEAR.
If you have any trouble installing a version of PHP, try running the same command but add the
-d option. This will send debug information to the console, instead of sending it to a log file.
phpbrew install -d 5.6.0 +default +sqlite
Switching PHP versions
So, at this point we should have a version of PHP installed.
If our installation was a success then PHPbrew will output a message like this:
Congratulations! Now you have PHP with php-5.6.0. To use the newly built PHP, try the line(s) below: $ phpbrew use php-5.6.0 Or you can use switch command to switch your default php version to php-5.6.0: $ phpbrew switch php-5.6.0
The first command listed
use will let you use PHP 5.6.0 while you’re in that console session. If you close the tab/window or restart your computer then you’ll be back to whichever version of PHP is the default.
The second command
switch will switch the default version of PHP that PHPbrew will go to on a new session.
Lets try setting the default version to be PHP 5.6.0, and see if it works.
$ phpbrew switch php-5.6.0 $ php -v PHP 5.6.0 (cli) (built: Sep 30 2014 15:30:22) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
The output above shows us exactly what we want to see:
If we now try installing the older PHP 5.5, we can once again use
$ phpbrew known to see which versions are available. Pick a version, and try to install it:
phpbrew install 5.5.17 +default +sqlite
This will install PHP 5.5.17 with the
sqlite variants. To then use PHP 5.5.17, we have to run another command:
$ phpbrew use php-5.5.17 $ php -v PHP 5.5.17 (cli) (built: Sep 30 2014 17:41:05) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
Now we can use PHP 5.5.17 in this session, and use PHP 5.6.0 again. As we used the
use command not
switch, when we open another tab or window, PHP 5.6.0 will once again be there.
PHPbrew vrs. System
When we are using a PHPbrew version of PHP, our bash session will be using a special path for the PHP version. We can find out which version is in use with the
$ which php /Users/phil/.phpbrew/php/php-5.6.0/bin/php
If we would like to stop using this phpbrew version of PHP and go back to the system version, we can use the
$ phpbrew off phpbrew is turned off. $ which php /usr/bin/php $ php -v PHP 5.4.24 (cli) (built: Jan 19 2014 21:32:15) Copyright (c) 1997-2013 The PHP Group Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
Once again we’re using the default version. You may not need this, but it is handy to know how to get rid of phpbrew. The
which command will also help you out with debugging.
PHPbrew by itself is a useful tool, and you might find this is all you need. That said, these versions of PHP can get complicated when you find that various projects need more extensions. PHPBrew can add PECL extensions, but not a project-by-project basis.
It also assumes you can remember which version of PHP an application should be using. It might not be the default, and running it under another version could cause problems.
To do this, we need to look at using another tool on top of PHPbrew.
VirtPHP lets you make isolated PHP environments on a single machine, like Python’s virtualenv. That might sound a little complicated but the idea is simple.
To start, you mark one directory which contains an application or component, and give it a name. Imagine we were working on “airpair-api” and its a PHP app, we’d want to make that its own environment.
Then, we could install PECL extensions that “airpair-api” needs, without affecting other applications.
That’s the theory, so let’s take a look at how we do that.
Go to the virtPHP releases page and find the latest release. It will have a link saying “virtphp.phar”, and you’ll want to right click and copy that URL.
$ wget https://github.com/virtphp/virtphp/releases/download/v0.5.1-alpha/virtphp.phar chmod +x virtphp.phar sudo mv virtphp.phar /usr/bin/virtphp
Now we can check to see if it is working:
$ virtphp -V virtPHP version v0.5.1-alpha 2014-08-13 16:05:47
VirtPHP maintains a relaxed approach to which version of PHP is in use. When you go to create an environment, it will take whichever version of PHP you have in your console session and reference that.
So, before we try to make a new environment, we need to be certain we are using the right version.
$ which php /Users/phil/.phpbrew/php/php-5.6.0/bin/php
Oops, it’s still using the default version and I want to make sure my codebase is working on PHP 5.5.
$ phpbrew use 5.5.17 $ which php /Users/phil/.phpbrew/php/php-5.5.17/bin/php
Perfect, the currently enabled version of PHP is 5.5.17, which in this example is the one we want.
Now we can make an environment.
virtphp create airpair-api
You will see a lot of output, and if goes well then you should see the following:
Your virtual php environment (airpair-api) has been created! You can activate your new environment using: ~$ source /Users/phil/.virtphp/envs/airpair-api/bin/activate
At this point the new environment is ready to use, but not enabled. Copy the command it gives you and run it, or run this shorter version:
$ source ~/.virtphp/envs/airpair-api/bin/activate
Now you should see the name of the environment
(airpair-api) in the console prompt, before the
$ character. This lets you know that you are in an environment, so you can deactivate it or act accordingly.
Playing in the Sandbox
Now we have this environment, we can install and configure things without affecting other PHP installations.
One great use-case for using environments is being able to install PECL extensions. Not only can you test how an app works with or without the extension, but you can try different versions too.
(airpair-api) $ pecl install xdebug (airpair-api) $ pecl install memcached-1.0.2
This helps us install the great debugging tool Xdebug, and install the [memcached] extension.
At the time of writing, the PECL command installs packages via the PEAR-based system. In future versions of virtPHP, PECL extensions will install via the new and improved Pickle system. This will remove a few issues that OS X seems to have with supporting PEAR.
Exiting an Environment
To check if you’re still using an environment, two things will help. The first clue is to see the environment name in brackets in your command prompt. The second is to use
which php and see if its pointing to a virtPHP environment.
(airpair-api) $ which php /Users/phil/.virtphp/envs/airpair-api/bin/php (airpair-api) $ deactivate $ which php /Users/phil/.phpbrew/php/php-5.6.0/bin/php
There you can see we were using the
airpair-api environment. Then after deactivating it, the console fell back to using 5.6.0 installed from PHPbrew, as that is default.
Playing with many installed versions like this can at first seem a little confusing. In reality, there is much less to learn here than trying to teach a beginner developer all about a full stack.
If a new developer was to try and build a basic PHP app, traditionally they would go through the following steps to get started:
- Virtual Hosts and /etc/hosts
- Hack the core OS PHP version
- Maybe install XAMPP/WAMP/MAMP instead
- Try to upgrade the core versions or *AMP versions
- Get confused that system PHP and MAMP PHP is different
- Try to install PECL extensions to MAMP version, but install them to system PHP instead
You can avoid a lot of that pain with a tool like Vagrant and a provision script, but that assumes that this beginner is in a team. If going solo, the beginner would have a much harder time getting started.
This is how the Ruby on Rails community has done things for years. Teach beginners a framework, abstract away a lot of the hard stuff, get them building and let them learn more about it all as they grow.
Grab your PHP version, install what you need, run the PHP development server with
php -S and only beef up your stack when (or if) you need to.
Dev/Prod parity is important, but sometimes you can get away with not caring too much if its just a simple little HTTP service. If you already have CI testing in place then this is even more true.
Finaly, even if you don’t want to run the code through the development server, having PHPbrew and virtPHP are still useful. You can install new versions as soon as they come out to play with the new syntax, and not break all your apps.