Environment variables hold settings outside your code, set by the server, hosting panel, Docker or a .env file. They are the standard place for secrets and for values that change between environments.
You met the basics in $_ENV and getenv(). Here is how to use them in a project.
Read a variable
<?php
putenv("APP_ENV=local"); // normally set outside PHP
echo getenv("APP_ENV") . "\n";
echo getenv("MISSING") === false ? "missing" : "set";
local
missing
A .env file for local development
On your own computer, typing variables into the server settings is awkward. A .env file lists them as KEY=value lines.
APP_ENV=local
APP_DEBUG=true
DB_HOST=127.0.0.1
DB_NAME=shop
DB_USER=root
DB_PASS=
Rules for the file:
- It is never committed to Git. Add
.envto.gitignore. - You commit a
.env.examplewith the names and harmless sample values, so others know what to set. - It lives outside the public web folder.
A tiny loader
<?php
function parseEnv(string $contents): array
{
$vars = [];
foreach (preg_split('/\R/', $contents) as $line) {
$line = trim($line);
if ($line === "" || str_starts_with($line, "#") || !str_contains($line, "=")) {
continue;
}
[$key, $value] = explode("=", $line, 2);
$vars[trim($key)] = trim($value, " \t\"'");
}
return $vars;
}
$env = parseEnv("# database\nDB_HOST=127.0.0.1\nDB_NAME=\"shop\"\n\nAPP_DEBUG=true");
print_r($env);
Array
(
[DB_HOST] => 127.0.0.1
[DB_NAME] => shop
[APP_DEBUG] => true
)
For real projects, use the vlucas/phpdotenv package. It handles quotes, comments, variable references and required variables:
composer require vlucas/phpdotenv
<?php
require __DIR__ . "/vendor/autoload.php";
$dotenv = Dotenv\Dotenv::createImmutable(dirname(__DIR__));
$dotenv->safeLoad();
$dotenv->required(["DB_HOST", "DB_NAME"]);
Types: everything is a string
Environment values are always strings. "false" is a non-empty string, which is truthy.
<?php
function envBool(string $value, bool $default = false): bool
{
$result = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
return $result ?? $default;
}
var_dump(envBool("true"));
var_dump(envBool("false"));
var_dump(envBool("0"));
var_dump(envBool("nonsense", true));
bool(true)
bool(false)
bool(false)
bool(true)
A typed Env helper
<?php
final class Env
{
public function __construct(private array $values) {}
public function string(string $key, string $default = ""): string
{
return (string) ($this->values[$key] ?? $default);
}
public function int(string $key, int $default = 0): int
{
return filter_var($this->values[$key] ?? null, FILTER_VALIDATE_INT) ?: $default;
}
public function bool(string $key, bool $default = false): bool
{
return filter_var($this->values[$key] ?? null, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ?? $default;
}
}
$env = new Env(["DB_PORT" => "3307", "APP_DEBUG" => "false", "DB_HOST" => "db.internal"]);
echo $env->string("DB_HOST") . ":" . $env->int("DB_PORT", 3306) . " debug=" . var_export($env->bool("APP_DEBUG", true), true);
db.internal:3307 debug=false
Where the values come from in production
- The hosting control panel (many hosts have an “environment variables” screen).
- Apache
SetEnv, PHP-FPMenv[...], orphp.ini. - Docker (
-e,env_file) and CI/CD secrets. - A
.envfile on the server, outside the web root, with strict file permissions.
Safety rules
- Never commit secrets. If one was committed once, rotate it.
- Never print the environment (
phpinfo(),print_r($_ENV)). - Never send server secrets to the browser.
- Give each environment its own keys.
- Use the least privilege key each service allows.
Prefix your own names
MYAPP_DB_HOST) when sharing a server with other applications. And remember that on some systems every process of the same user can read the environment of others, so do not run mixed-trust sites under one account.