Run different php-cli versions with Docker

I am working on a small PHP library that should use some new features from PHP 7, for example scalar type declarations and return type declarations. But my current Debian 8 has only PHP 5.6.29 for me at the moment. The unstable distribution sid is no option to me and in general I try to avoid installing a specific PHP interpreter on my OS. Fortunately I need PHP only on the command line to test my library so I can use Docker to switch between the versions.

A PHP 7 only Hello World

Let us start with a PHP 7 only Hello World script. The first argument on the command line will be appended to the string Hello . The script will append the string PHP if there is no first argument.

<?php

function hello(string $name) : string
{
    return "Hello " . $name . "\n";
}

$name = $argv[1] ?? "PHP";
echo hello($name);

As expected is the PHP 5.6 interpreter on my operating system not able to parse this PHP code.

php HelloWorld.php
PHP Parse error:  syntax error, unexpected ':', expecting '{' in HelloWorld.php on line 3

Run a single PHP script in Docker

Let us run the same PHP script in the PHP Docker container with PHP 7.1.

docker run -it --rm -v "$PWD"/HelloWorld.php:/HelloWorld.php php:7.1-cli php /HelloWorld.php Docker
Hello Docker

Expand the minimal example

We will expand the minimal Hello World example from above with some dependencies that should be installed via Compsoer. The current project tree looks like this.

.
|-- vendor/
|-- composer.json
`-- HelloWorld.php

With a minimal composer.json that is requiring symfony/console.

{
    "require": {
        "php": "~7.0",
        "symfony/console": "^3.2"
    }
}

Composer install via Docker container

We do not need to install composer on our operating system, there is a Composer Docker container. The following command will install our dependencies.

docker run --rm -u $UID -v "$PWD":/app composer/composer install
Cannot create cache directory /composer/cache/repo/https---packagist.org/, or directory is not writable. Proceeding without cache
Cannot create cache directory /composer/cache/files/, or directory is not writable. Proceeding without cache
Loading composer repositories with package information
Updating dependencies (including require-dev)
  - Installing psr/log (1.0.2)
    Downloading: 100%

  - Installing symfony/debug (v3.2.2)
    Downloading: 100%

  - Installing symfony/polyfill-mbstring (v1.3.0)
    Downloading: 100%

  - Installing symfony/console (v3.2.2)
    Downloading: 100%

symfony/console suggests installing symfony/event-dispatcher ()
symfony/console suggests installing symfony/filesystem ()
symfony/console suggests installing symfony/process ()
Writing lock file
Generating autoload files

Run more than a single PHP script in Docker

I have changed the HelloWorld.php script to use the symfony/console. The script is mostly doing the same thing as before.

<?php
require __DIR__.'/vendor/autoload.php';

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

function hello(string $name) : string
{
    return "Hello " . $name . "\n";
}

(new Application('hello', '1.0.0'))
    ->register('hello')
    ->addArgument('name', InputArgument::OPTIONAL, 'The name')
    ->setCode(function(InputInterface $input, OutputInterface $output) {
        $name = $input->getArgument('name') ?? "PHP";
        $output->write(hello($name));
    })
    ->getApplication()
    ->setDefaultCommand('hello', true)
    ->run();

The single PHP script command from above is producing the following error now.

docker run -it --rm -v "$PWD"/HelloWorld.php:/HelloWorld.php php:7.1-cli php /HelloWorld.php Docker

Warning: require(//vendor/autoload.php): failed to open stream: No such file or directory in /HelloWorld.php on line 2

Fatal error: require(): Failed opening required '//vendor/autoload.php' (include_path='.:/usr/local/lib/php') in /HelloWorld.php on line 2

So we need to include the hole project folder into the the Docker container like the following command is doing.

docker run -it --rm -v "$PWD":/usr/src/hello -w /usr/src/hello php:7.1-cli php HelloWorld.php Docker
Hello Docker
Next Previous