DEV Community

Cover image for Handling multiple environments in raw PHP
Manuel
Manuel

Posted on

Handling multiple environments in raw PHP

This post complements to these ones:

I can imagine you have at least 4 different environments in your app: one for developing, one for your CI, one for staging and one for production.

Let's see how we can handle them with ease.

In our case, if you come from previous posts, you know we are using PHP-DI. It's not completely necessary though, you can experiment with this solution depending on your app.

So we are going to have multiple config files outside src folder named config, in which there are going to be as many files as environments you have, for example:

  • ci.php
  • prod.php
  • dev.php

In which, let's say you need to specify your database credentials, so let's return something like this:

return [
    'databaseConfig' => [
        'driver' => 'mysql',
        'host' => '127.0.0.1',
        'username' => 'root',
        'password' => 'toor',
        'database' => 'database',
        'port' => 3305,
    ],
];

And then we need to load it from several places, for example in our (previously explained) FixtureLoader, for this we are going to use the following class:

class Config
{
    private static array $config = [];

    public static function getConfig()
    {
        if (!self::$config) {
            $_SERVER['PHP_ENV'] ??= 'default'; // IN CASE YOU NEED A DEFAULT ENV
            self::$config = include ("{$_SERVER['PHP_ENV']}.php");
        }

        return self::$config;
    }
}

Where does this $_SERVER['PHP_ENV'] come from?

  • In case you are running tests you can easily define it like PHP_ENV=e2e phpunit ...
  • Web server configuration

For example nginx's configuration:

server {
    ...

    fastcgi_param PHP_ENV env-desired;

    ...
}

This is quite practical since you can have multiple environments running at the same time, you just need as many web server configurations as environments you need running.

Then, you can configure your container:

$container = new DI\ContainerBuilder();

$container->useAutowiring(true);
$container->useAnnotations(false);

$container->addDefinitions([
    Config::getConfig(),
    DatabaseService::class => function (ContainerInterface $container) {
        $databaseService = new DatabaseService($container->get('databaseConfig'));
        $databaseService->connectToDb();

        return $databaseService;
    },
]);

if ($_SERVER['PHP_ENV'] == 'prod') {
    $container->enableCompilation(__DIR__ . '/cache');
}

$container = $container->build();

As you see, whenever we get DatabaseService from the container, it will get from its constructor the databaseConfig we have set in the specified environment's file.

Top comments (1)

Collapse
 
carlillo profile image
Carlos Caballero

Thanks!