I recently chose to write a simple command to run in a bash-like environment with PHP.
Why PHP? In short, because I want. The command communicates with remote Rest and GraphQL APIs and needs some level of control over the log messages (errors, info, debug…). Also, I would like to expose some arguments and options with validation rules.
My stack was:
- guzzlehttp/guzzle: To communicate with remote APIs.
- monolog/monolog: To control my log streams and formats
- filp/whoops: To generate beautiful error messages in CLI
- symfony/console: To easily parse and manage command arguments, options, and responses
- vlucas/phpdotenv: To allow configuration of internal dependencies using environment variables
As I am not an expert in writing CLI with PHP, I’ve found some troubles while making the internal dependencies access the environment variables. And that led me to write this post.
The first attempt was made using that snippet:
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__); $dotenv->load();
And to read variables inside my code I used:
$myValue = $_ENV['SOME_DEPS_VARIABLE'];
So I created a file .env , put my variables inside, and called the command in local bash: IT’S WORKING!
But I was wrong about some details: the code will run also using a Docker Container, with variables defined on system ENV (the classic export way).
After many tries, rereading the project README I finally found what I wanted and needed:
$dotenv = Dotenv\Dotenv::createUnsafeImmutable(__DIR__); $dotenv->safeLoad();
To read the env values I replaced the use of superglobal $_ENV with the $_SERVER:
$myValue = $_SERVER['SOME_DEPS_VARIABLE'];
What you (and I) need to know:
- The superglobal $_SERVER is more reliable for accessing environment variables with PHP (in that case, getenv should work too, but is not thread-safe)
- Use the $dotenv->safeLoad() when you can’t guarantee the environment variables will be defined with a file .env