data types and standard library
Environment and Config Files
Good config code keeps secrets out of source control, parses values into useful types, validates required settings early, and makes defaults explicit. Bad config code spreads getenv() calls everywhere and fails later with vague errors.
Read environment variables at the edge
Environment variables arrive as strings or false. Convert them before the rest of the application sees them.
<?php
declare(strict_types=1);
putenv('APP_ENV=local');
$appEnv = getenv('APP_ENV');
if (!is_string($appEnv) || $appEnv === '') {
throw new RuntimeException('APP_ENV is required.');
}
echo $appEnv . PHP_EOL;
// Prints:
// local
In a real project, read environment variables during application bootstrapping and pass typed config into services.
Parse INI with typed values
PHP can parse INI strings and files. INI_SCANNER_TYPED converts values such as true, false, and numbers where possible.
<?php
declare(strict_types=1);
$ini = <<<'INI'
app_env=local
debug=true
max_upload_mb=10
INI;
$config = parse_ini_string($ini, false, INI_SCANNER_TYPED);
if (!is_array($config)) {
throw new RuntimeException('Config could not be parsed.');
}
echo $config['app_env'] . PHP_EOL;
echo $config['debug'] ? 'debug on' : 'debug off';
echo PHP_EOL;
echo $config['max_upload_mb'] . PHP_EOL;
// Prints:
// local
// debug on
// 10
Typed parsing helps, but you still need validation. A misspelled key can still be missing.
Validate required settings
Turn loose config arrays into a known application shape.
<?php
declare(strict_types=1);
function requireStringConfig(array $config, string $key): string
{
if (!isset($config[$key]) || !is_string($config[$key]) || trim($config[$key]) === '') {
throw new InvalidArgumentException($key . ' must be a non-empty string.');
}
return $config[$key];
}
$config = ['database_dsn' => 'mysql:host=db;dbname=app'];
echo requireStringConfig($config, 'database_dsn') . PHP_EOL;
// Prints:
// mysql:host=db;dbname=app
Failing fast during startup is better than discovering missing config halfway through a customer request.
Convert booleans deliberately
Do not treat every non-empty string as true. The string 'false' is truthy in PHP.
<?php
declare(strict_types=1);
function envBool(string $value): bool
{
$parsed = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
if ($parsed === null) {
throw new InvalidArgumentException('Expected a boolean value.');
}
return $parsed;
}
echo envBool('false') ? 'on' : 'off';
echo PHP_EOL;
// Prints:
// off
This matters for settings such as debug mode, maintenance mode, feature flags, and queue workers.
Keep secrets out of committed config
Commit examples such as .env.example or config/example.ini, but do not commit real passwords, API keys, tokens, or private keys.
<?php
declare(strict_types=1);
$requiredSecrets = ['DATABASE_PASSWORD', 'PAYMENT_API_KEY'];
foreach ($requiredSecrets as $name) {
echo $name . ' must be provided by the environment' . PHP_EOL;
}
// Prints:
// DATABASE_PASSWORD must be provided by the environment
// PAYMENT_API_KEY must be provided by the environment
The application should document required secrets without exposing their values.
YAML and TOML need parsers
PHP has built-in support for INI, but YAML and TOML usually come from Composer packages or framework config loaders. The rule is the same: parse once, validate the shape, and pass typed values into the application.
<?php
declare(strict_types=1);
$parsedYamlLikeConfig = [
'cache' => [
'enabled' => true,
'ttl_seconds' => 300,
],
];
echo $parsedYamlLikeConfig['cache']['enabled'] ? 'cache on' : 'cache off';
echo PHP_EOL;
// Prints:
// cache on
Do not invent a YAML or TOML parser with string splitting. Use a maintained parser and validate the result.
What to remember
Read raw environment and config files at the application boundary. Convert strings to real types, validate required keys, document secrets without committing them, and keep config access centralised so the rest of the code can depend on clear values.
Practice
Task: Load typed application config
Write a small config loader from an INI string.
Requirements
- Use
declare(strict_types=1);. - Parse an INI string with
INI_SCANNER_TYPED. - Require
app_envto be a non-empty string. - Require
debugto be a boolean. - Require
max_upload_mbto be a positive integer. - Return a typed config array with clearer key names.
- Print the loaded values.
- Show one invalid config case by catching the exception.
- Include the expected output as comments in the same PHP code block.
The loader should fail early when config is missing or has the wrong type.
Show solution
<?php
declare(strict_types=1);
function loadAppConfig(string $ini): array
{
$config = parse_ini_string($ini, false, INI_SCANNER_TYPED);
if (!is_array($config)) {
throw new InvalidArgumentException('Config could not be parsed.');
}
if (!isset($config['app_env']) || !is_string($config['app_env']) || trim($config['app_env']) === '') {
throw new InvalidArgumentException('app_env must be a non-empty string.');
}
if (!isset($config['debug']) || !is_bool($config['debug'])) {
throw new InvalidArgumentException('debug must be a boolean.');
}
if (!isset($config['max_upload_mb']) || !is_int($config['max_upload_mb']) || $config['max_upload_mb'] < 1) {
throw new InvalidArgumentException('max_upload_mb must be a positive integer.');
}
return [
'environment' => $config['app_env'],
'debug' => $config['debug'],
'maxUploadMegabytes' => $config['max_upload_mb'],
];
}
$validIni = <<<'INI'
app_env=local
debug=true
max_upload_mb=10
INI;
$config = loadAppConfig($validIni);
echo $config['environment'] . PHP_EOL;
echo $config['debug'] ? 'debug on' : 'debug off';
echo PHP_EOL;
echo $config['maxUploadMegabytes'] . ' MB' . PHP_EOL;
try {
loadAppConfig("app_env=local\ndebug=maybe\nmax_upload_mb=10");
} catch (InvalidArgumentException $exception) {
echo $exception->getMessage() . PHP_EOL;
}
// Prints:
// local
// debug on
// 10 MB
// debug must be a boolean.
The loader turns a loose config source into a predictable application shape. That keeps validation near the boundary and avoids scattered type checks throughout the codebase.