Both PHP 7.0 and the upcoming PHP 7.1 release are fairly benign releases. They do not break backwards compatibility except in a few edge cases. If you’ve not yet moved to PHP 7.0, check out our posts taggedphp7 for details on what might trip you up there.
UPDATE: Based on the advice in this article “Keep it small: a closer look at Docker image sizing”, I’ve updated the Dockerfile. It’s not as easy to read, but it minimizes all the RUN commands into a single command.
Regardless of what version you are moving to, 7.0 or 7.1, you are going to want to test your application before you make the move in production. Sometimes that is difficult though you need a server properly configured, you need someone to manage it, most importantly, you need unit tests. While I can’t help you with that last one – other than point you to@grmpyprogrammer who will publicly abuse you until you write them – I can help you with the “where to test” problem.
Containers to the rescue
This solution relies on Docker. If you don’t have Docker installed, you will want to do that first. Docker is available for almost anything and will run on older hardware as well as brand new servers. The code for this article was developed on a 2012 MacBook Air with 8GB of RAM. That’s not what you would call a powerhouse.
So step 1 is to install Docker.
Building a platform
Once you have Docker, you need to build a container that contains everything you need to test. Mainly, this is PHP. If your Unit Tests require a database and you aren’t mocking it, then this won’t help you. This platform contains PHP and that is all.
Docker builds an entire environment inside the container, this means that it needs an operating system. I chose Alpine Linux because it was the smallest footprint. By the time we install everything we are still at 800MB, but that’s a far cry from some of the more popular Linux distros that weigh in at 800mb to 1.5GB as the base. It was pointed out that Alpine, because of the C compiler it uses is not the best choice of distros for testing PHP. This may be. However, PHP compiles nicely on Alpine and we really aren’t testing PHP, we are building a platform for testing our applications. So far in my very limited testing, it has worked flawlessly.
In a blank directory somewhere on you drive, create a Docker file and paste this into it.
FROM alpine:3.4
MAINTAINER Cal Evans <cal@calevans.com>
RUN apk add --no-cache bash vim wget sudo gcc autoconf automake make libtool \
re2c flex bison git libc-dev openssl-dev libxml2-dev zlib-dev \
curl-dev libpng-dev icu-dev libmcrypt-dev libedit-dev g++ bzip2-dev \
libxslt-dev; \
cd /root; \
git clone https://github.com/php/php-src.git; \
wget -U "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:47.0) Gecko/20100101 Firefox/47.0" https://devzone.zend.com/downloads/buildphp.sh -O /root/buildphp.sh; \
sh buildphp.sh; \
cd /root; \
wget https://getcomposer.org/installer; \
php installer; \
mv composer.phar /usr/bin/composer; \
adduser -D cpkelly
Once you have that saved, lets’ build. Drop to your command line and navigate to the directory where you saved the Dockerfile. When you are there, enter this command.
docker build --tag php7.1_buildbox .
This will take a while to run. On my little laptop with a very fast ‘Net connection, it takes about 30 minutes. Your mileage may vary depending on your laptop speed and connection speed.
Let’s test
When it’s done, we are ready to test…almost. First, you need to move your application into the container.
docker run -ti php7.1_buildbox /bin/sh
This will drop you into the container at a # prompt. You are now root. The problem is that if you use composer, composer won’t run as root. So I recommend immediately dropping into the user we added cpkelly. Once you’ve switched users, change to that user’s home directory.
/ # su - cpkelly
/ $ cd
~ $
There, now you are ready. For this example, I am going to be testing the open source blogging project Sculpin. This is just to show you what needs to be done. You will need to substitute your repo for Sculpin’s and adjust the commands accordingly.
$ git clone https://github.com/sculpin/sculpin.git
~ $ cd sculpin/
~/sculpin $ composer update
~/sculpin $ vendor/bin/phpunit
I’ve cut out all the messages that each command spews because they aren’t important to the process.
Note that I specifically reference the PHPUnit that is in Sculpin’s vendor/bin directory. Most major projects add PHPUnit to their require-dev. This way they get the version that their tests were written with and not the most recent version. This is important. If you are testing using the most recent versino of PHP then you can use composer to install it before testing if your project doesn’t include it in the composer.json.
If all goes correctly, you should see something like this.
~/sculpin $ vendor/bin/phpunit
PHPUnit 3.7.38 by Sebastian Bergmann.
Configuration read from /home/cpkelly/sculpin/phpunit.xml.dist
..............................
Time: 998 ms, Memory: 6.00MB
OK (30 tests, 91 assertions)
This is PHPUnit telling you that all is well with the world and that specifically, your application should run on PHP 7.1.
This isn’t CI
Hey! You are paying attention! No, this isn’t CI or CD, this is a sandbox for you to play in. Yes, you could do all of this by just adding PHP 71 to your travis.yaml file or whatever controls your CI. That would tell you if your app works, but if it didn’t, you would still have to try and play wack-a-mole by updating, committing, waiting for CI to run, find the next bug. This way, you have a PHP 7.1 sandbox to play in. You can find and fix the issues right here.
This Docker file could be better
Yup, you are right. I am not Chris (Docker Man Tank) Tankersly. This is my first shot at writing my own Docker file. All I can say is that “it works”. I had a couple of people test it on other laptops and it seems to work fine on a variety of platforms. This is not a guarantee that it will work for you.
If you have a better way to do it, blog it, Let me know, I’ll link to it from here.
Future proof
One thing this solution has going for it is that it is useful beyond PHP 7.1. Hopefully, there will be a PHP7.2, .3, .4, etc. Eventually, there will be a PHP 8.0! One thing that should not change is the Core’s methodology of branching versions. As long as they keep using git and branching new versions you can use this sandbox to test any of them.
One of the things the Dockerfile does is pull down a bash script, buildphp.sh. If you open that inside your container, you will see that it checks out the PHP-7.1 branch. You can edit this to check out any branch of PHP. So when 7.2 starts, you just change this script and run it. Voila! You now have a PHP 7.2 build box.
The other reason all of this is broken out into its own script is that during development, the PHP-7.1 branch changes often. At any time, you can update your version of PHP to the absolute latest build by starting your build box, going into the root dir, and running buildphp.sh. It will pull the latest version of the repo down before building and installing PHP. Then swap to cpkelly pull the latest version of your repo, and run PHPUnit.
:Conclusion
Regardless of how you do it, you need to be testing your application against current and future version fo PHP. You may not be planning to use a future version, but it is good to know that you can if you need to. This solution does not replace a good CI plan. It will, however, give you a sandbox to play in without messing up your existing laptop.