A simple and lightweight .env loader for PHP projects.
Via Composer:
composer require codemonster-ru/envCreate a .env file in the root of your project:
APP_NAME=MyApp
FEATURE_ENABLED=true
FEATURE_DISABLED=false
OPTIONAL_VALUE=null
EMPTY_VALUE=empty
SSR_URL="http://localhost:3000"
WITH_SPACES="spaced value"
INLINE_COMMENT=works # comment
ESCAPED_HASH="foo#bar"
MULTILINE="line1\nline2"
export EXPORTED_VALUE=exportedLoad .env in your app:
<?php
require __DIR__ . '/vendor/autoload.php';
use Codemonster\Env\Env;
use Codemonster\Env\EnvLoader;
Env::load(__DIR__ . '/.env');
echo Env::get('APP_NAME'); // "MyApp"Optional casting:
Env::getCast('FEATURE_ENABLED', false, true); // true
Env::getCast('OPTIONAL_VALUE', 'default', true); // nullCommon options:
// Encoding conversion (mbstring required)
Env::load(__DIR__ . '/.env', 'UTF-8');
// Size limit in bytes (negative size is invalid)
Env::load(__DIR__ . '/.env', null, 1048576);
Env::loadString("KEY=value\n", null, false, 1024);
// Strict resolve (throws if ${VAR} or $VAR is missing)
Env::load(__DIR__ . '/.env', null, null, true);
// Optional file (returns false if missing/unreadable/too large)
Env::safeLoad(__DIR__ . '/.env');Parsing helpers:
Env::parse("KEY=value\n");
Env::parse("KEY=value\n", null, true); // strict, rejects duplicates
Env::parseToArray("KEY=value\n");
Env::parseToArray("KEY=value\n", null, true); // strict, rejects duplicatesMultiple files and glob:
Env::loadFiles([__DIR__ . '/.env', __DIR__ . '/.env.local']);
Env::loadFiles([__DIR__ . '/*.env'], null, null, false, true, GLOB_NOSORT);ASCII-only names:
Env::setDefaultParser(new DefaultParser(true));
Env::loadString("VALID_NAME=ok\n");Isolated loader instance:
$loader = new EnvLoader();
$loader->loadFile(__DIR__ . '/.env');
$loader->resetLoaded();
$loader->safeLoadFile(__DIR__ . '/.env');
$loader->loadFile(__DIR__ . '/.env', null, 1048576, true);
$loader->loadString("KEY=value\n");
$loader->loadString("KEY=${VAR}\n", null, true);
$loader->loadFiles([__DIR__ . '/.env', __DIR__ . '/.env.local']);Notes:
- When encoding is null, no conversion is performed, even if mbstring is available.
- UTF-8 BOM is stripped automatically.
- Loading
.envfiles into$_ENV,$_SERVER, and viaputenv(). - Does not override variables already present in
$_ENV,$_SERVER, orgetenv(). - Values are returned as strings by default;
Env::getCast()enables optional casting. - Quoted strings with escaped quotes and
\n,\r,\t,\v,\fin double quotes (single quotes are literal). - Inline comments start with
#in unquoted values (use quotes to keep a literal#). - Unquoted values cannot contain whitespace.
export KEY=valuesupport.- Unknown escape sequences in double quotes throw
InvalidFileException. - Strict parsing: invalid lines, invalid variable names, and unclosed quotes throw
InvalidFileException. ${VAR}and$VARexpansion are supported in quoted and unquoted values.${VAR}and$VARexpand in double quotes and unquoted values; single quotes keep literals.- Lines without
=are treated as empty strings. - Re-loading updates variables that were previously loaded by this library.
- Optional encoding conversion (requires
mbstring). - Optional strict resolve mode throws on unresolved
${VAR}or$VARreferences. - Default name rules allow Unicode letters/numbers; ASCII-only names are optional (via
DefaultParser(true)).
| Method | Return format |
|---|---|
Env::parse() |
Raw entries: [[name, value, vars], ...] |
Env::parseToArray() |
Associative map: ['NAME' => 'value', ...] |
EnvParser::parseStringRaw() |
Raw entries: [[name, value, vars], ...] |
Strict mode throws InvalidFileException on duplicate names for parse() and parseToArray().
loadFiles()processes paths in the order provided.- Glob patterns are expanded using
glob()withGLOB_BRACEby default. - Glob matches are sorted to keep load order stable.
- Use the optional
globFlagsparameter to changeglob()behavior. - If
strictResolveis true, unresolved${VAR}or$VARreferences in any loaded file will throwInvalidFileException. - If
shortCircuitis true, the first successfully loaded file stops further processing. - If
shortCircuitis false, missing files raiseInvalidPathException.
| Scenario | Exception |
|---|---|
| Invalid syntax, invalid name, bad escapes | Codemonster\Env\Exception\InvalidFileException |
| Invalid or unsupported encoding | Codemonster\Env\Exception\InvalidEncodingException |
| Missing or unreadable file | Codemonster\Env\Exception\InvalidPathException |
You can provide your own loader by implementing Codemonster\Env\LoaderInterface:
<?php
use Codemonster\Env\Env;
use Codemonster\Env\LoaderInterface;
class MyLoader implements LoaderInterface
{
public function resetLoaded(): void
{
// reset internal state
}
public function loadFile(
string $path,
?string $encoding = null,
?int $maxBytes = null,
bool $strictResolve = false
): void
{
// custom loading logic
}
public function safeLoadFile(
string $path,
?string $encoding = null,
?int $maxBytes = null,
bool $strictResolve = false
): bool
{
// return false if missing/unreadable
return false;
}
}
Env::setDefaultLoader(new MyLoader());You can provide a custom parser to EnvLoader by implementing Codemonster\Env\ParserInterface:
<?php
use Codemonster\Env\DefaultParser;
use Codemonster\Env\EnvLoader;
use Codemonster\Env\ParserInterface;
class MyParser implements ParserInterface
{
public function parseStringRaw(string $content, ?string $encoding = null): array
{
return (new DefaultParser())->parseStringRaw($content, $encoding);
}
public function expandVariables(string $value, array $vars): string
{
return (new DefaultParser())->expandVariables($value, $vars);
}
public function expandVariablesWithReport(string $value, array $vars): array
{
return (new DefaultParser())->expandVariablesWithReport($value, $vars);
}
}
$loader = new EnvLoader(new MyParser());DefaultParser accepts an optional boolean for ASCII-only variable names:
$parser = new DefaultParser(true); // match phpdotenv name rulesYou can run tests with the command:
composer test