This article is part of my #100DaysOfCode and #100DaysOfBlogging challenge. R1D6


[The Twelve-Factor App] requires strict separation of config from code.

Taken from factor three of The Twelve-Factor App.

Today I am studying about how to achieve this requirement making usage of phpdotenv in a Zend Expressive context.

I will not go into details on and advantages of this concept. A leave that up to other resources.

phpdotenv

This package

Loads environment variables from .env to getenv(), $_ENV and $_SERVER automagically.

It has a clean setup and interface. To load an .env file use

$dotenv = Dotenv\Dotenv::create(__DIR__);
$dotenv->load();

Then you can access it via

$s3Bucket = getenv('S3_BUCKET');
$s3Bucket = $_ENV['S3_BUCKET'];
$s3Bucket = $_SERVER['S3_BUCKET'];

The documentation mentions also the possibility to access variable through the request class. This is out-of-scope of this blog entry, since I want to access env vars only in configuration files.

Install phpdotenv

I install the package via Composer.

composer require vlucas/phpdotenv

Create a dotenv file

Next, I create a .env file.

DOCTRINE_CONNECTION_HOST="localhost"
DOCTRINE_CONNECTION_PORT="3306"
DOCTRINE_CONNECTION_USER="db_user"
DOCTRINE_CONNECTION_PASSWORD="my-53cr37"
DOCTRINE_CONNECTION_DBNAME="database"
DOCTRINE_CONNECTION_charset="utf8mb4"

Load dotenv

Now phpdotenv needs to be put to work and do its magic. In my index.php I add the following two lines right after requiring the composer autoload file.

$dotenv = Dotenv\Dotenv::create(__DIR__);
$dotenv->load();

Load configuration from dotenv

My configuration file with the database is updated, to use the env vars now available through getenv().

<?php

declare(strict_types = 1);

return [
    'doctrine' => [
        'connection' => [
            'orm_default' => [
                'params' => [
                    'host'     => getenv('DOCTRINE_CONNECTION_HOST'),
                    'port'     => getenv('DOCTRINE_CONNECTION_PORT'),
                    'user'     => getenv('DOCTRINE_CONNECTION_USER'),
                    'password' => getenv('DOCTRINE_CONNECTION_PASSWORD'),
                    'dbname'   => getenv('DOCTRINE_CONNECTION_DBNAME'),
                    'charset'  => getenv('DOCTRINE_CONNECTION_CHARSET'),
                ],
            ],
        ],
    ],
];

Goal accomplished

A quick check on my API confirms that the env vars are utilized correctly. 👍