Settings and environment
An application has values that differ between your computer and the server: the database password, debug mode, the site name. They are not written directly into code. Such values are kept in a .env file, and the code reads them from one place — the settings array.
Installation
The .env file is read by the phpdotenv package:
composer require vlucas/phpdotenvThe .env file
Create a .env file by hand in the project root, next to composer.json:
APP_DEBUG=true
SITE_NAME="My blog"Each line is a name and a value. These are environment variables: on another server the same file holds different values.
Loading
The file is loaded in config/bootstrap.php, right after the autoloader:
// config/bootstrap.php
require __DIR__ . '/../vendor/autoload.php';
Dotenv\Dotenv::createImmutable(__DIR__ . '/..')->safeLoad();After this line the values are available in the $_ENV array. The safeLoad() method does not throw if the file is missing — on a server the variables may be set another way.
The settings array
Create config/settings.php. It is the only place where code touches $_ENV:
// config/settings.php
return [
'debug' => filter_var($_ENV['APP_DEBUG'] ?? false, FILTER_VALIDATE_BOOL),
'site_name' => $_ENV['SITE_NAME'] ?? 'Blog',
];The file returns a plain array. Values from .env are always strings, so filter_var() turns the string true or false into a boolean.
Settings in the container
To make the settings available to the rest of the application, add them to config/container.php under the name settings:
// config/container.php
return [
'settings' => fn () => require __DIR__ . '/settings.php',
];The other entries of the file stay in place — one line is added.
Using them
The container cannot supply a plain value by itself: the string type does not say which string is wanted. So a class that needs a setting gets a definition:
// config/container.php
use App\Action\HomeAction;
use Psr\Container\ContainerInterface;
return [
'settings' => fn () => require __DIR__ . '/settings.php',
HomeAction::class => fn (ContainerInterface $c) => new HomeAction(
$c->get('settings')['site_name'],
),
];// src/Action/HomeAction.php
final class HomeAction
{
public function __construct(private string $siteName) {}
public function __invoke(Request $request, Response $response): Response
{
$response->getBody()->write($this->siteName);
return $response;
}
}The home page shows "My blog". Change SITE_NAME in .env and reload the page — the text changes without touching the code.
The example file
Passwords will appear in .env later, so it is not added to version control — put .env into the .gitignore file. Next to it keep .env.example with the same names but without secret values: it shows which variables the project needs.
Common mistake
Writing (bool) $_ENV['APP_DEBUG'] does not work as expected: the string false is not empty, and PHP treats it as true. Debug mode ends up enabled on the server. For boolean values use filter_var(..., FILTER_VALIDATE_BOOL).