symfony/dotenv
Symfony Dotenv reads .env files and loads variables into PHP’s environment, exposing them via $_ENV and $_SERVER. Supports loading multiple files, overriding existing vars, and environment-specific .env.local/.env.$APP_ENV variants.
Install the package (if not using Laravel’s built-in Dotenv):
composer require symfony/dotenv
Note: Laravel 10+ already bundles a Dotenv-compatible solution (vlucas/phpdotenv). Use this package only for non-Laravel contexts or Symfony integration.
Basic Usage (e.g., in a CLI command or standalone script):
use Symfony\Component\Dotenv\Dotenv;
$dotenv = new Dotenv();
$dotenv->load(__DIR__.'/../../.env'); // Load from project root
Access variables via $_ENV['VAR_NAME'] or $_SERVER['VAR_NAME'].
First Use Case:
.env.local, .env.prod) in a Symfony-based CLI tool or Lumen app:
$dotenv->loadEnv(__DIR__.'/../../.env'); // Auto-loads .env.local, .env.prod, etc.
.env files):
$dotenv->loadEnv(__DIR__.'/../../.env'); // Loads:
// .env
// .env.local
// .env.prod.local (if APP_ENV=prod)
$dotenv->load(
__DIR__.'/config/.env.db',
__DIR__.'/config/.env.cache'
);
$dotenv->overload(__DIR__.'/../../.env.local');
${VAR} references after all files are loaded):
# .env
DB_HOST=localhost
DB_PORT=${DB_PORT:-3306} # Defaults to 3306 if DB_PORT is unset
use Symfony\Component\Console\Application;
use Symfony\Component\Dotenv\Dotenv;
$dotenv = new Dotenv();
$dotenv->load(__DIR__.'/../.env');
$app = new Application();
$app->run();
# config/services.yaml
services:
App\Service\ConfigService:
arguments:
$dbHost: '%env(DB_HOST)%' # Resolved via $_ENV
php bin/console debug:dotenv
.env files (check for BOM, syntax errors):
try {
$dotenv->load(__DIR__.'/invalid.env');
} catch (\Symfony\Component\Dotenv\Exception\PathException $e) {
// Handle invalid paths
}
env() helper (if migrating to Symfony/Dotenv):
function env(string $key, $default = null) {
return $_ENV[$key] ?? $_SERVER[$key] ?? $default;
}
// In AppServiceProvider::boot()
if (!app()->environment('local')) {
$dotenv = new Dotenv();
$dotenv->load(__DIR__.'/../../.env.prod');
}
$_ENV vs. $_SERVER Precedence:
$_ENV and $_SERVER. In Laravel, $_SERVER takes precedence over $_ENV by default.getenv() or $_ENV explicitly to avoid surprises:
$value = getenv('VAR_NAME'); // Always checks $_ENV first
Variable Expansion Order:
${VAR} references are resolved after all files are loaded. Overriding a variable in a later file may break expansions:
# .env
APP_URL=http://${DOMAIN}
DOMAIN=example.com
Fix: Use overload() for critical overrides or restructure files.BOM (Byte Order Mark) Errors:
.env files with BOM (common in UTF-8 files from Windows) throw exceptions..env files as UTF-8 without BOM (use VS Code’s "Save with UTF-8" option).Laravel Caching Conflicts:
.env mid-request won’t reflect until cache is cleared.php artisan config:clear or disable caching in config/caching.php.Self-Referencing Variables:
A=${B} and B=${A}) cause infinite loops.A=${B:-default_value}
B=some_value
php -r "print_r($_ENV);"
$dotenv->setPath(__DIR__.'/custom/path'); // Override default path
$dotenv->load(__DIR__.'/test.env', [], false); // 3rd arg: $override=false
Custom File Paths:
putenv('SYMFONY_DOTENV_PATH=/custom/env/path');
$dotenv->loadEnv('/custom/env/path/.env');
Subclassing for Validation:
use Symfony\Component\Dotenv\Dotenv as BaseDotenv;
class CustomDotenv extends BaseDotenv {
protected function parse(string $content): array {
$vars = parent::parse($content);
// Add custom validation (e.g., regex checks)
return $vars;
}
}
Integration with Laravel’s bootstrap/app.php:
$dotenv = new \Symfony\Component\Dotenv\Dotenv();
$dotenv->load(__DIR__.'/../.env');
Warning: Place this before Laravel’s Dotenv initialization to avoid conflicts.
.env in production unless necessary (Symfony Dotenv is lightweight but still parses files).overload() sparingly—it reprocesses all variables.APP_DEBUG Handling:
Symfony Dotenv doesn’t set APP_DEBUG by default. Use:
APP_DEBUG=true
Or manually in bootstrap/app.php:
define('APP_DEBUG', (bool) getenv('APP_DEBUG'));
$this->app->bind('env', function () {
return $_ENV;
});
How can I help you explore Laravel packages today?