wilycode / dotenv
Strict, lightweight .env file reader and loader for PHP.
Requires
- php: ^8.4
Requires (Dev)
- phpunit/phpunit: ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-12 20:50:00 UTC
README
A lightweight, strict .env file reader and loader for PHP 8.4+.
Keep application configuration in an .env file, read it as strings, and optionally load it into the PHP process. No framework or third-party runtime dependencies are required.
WilyCode PHP Ecosystem
Part of WilyCode — a collection of independent, reusable PHP components. Each package has its own repository, releases, and Composer installation.
Features
- Read
.envfiles without changing the process environment. - Load values into
getenv(),$_ENV, and$_SERVERwhen needed. - Preserve all values as strings — no automatic type conversion.
- Support
export, comments, single- and double-quoted values, and${NAME}expansion. - Use
\${NAME}inside double quotes to keep a placeholder literal. - Preserve existing environment variables by default; allow explicit overwrites.
- Report invalid syntax and missing or unreadable files with clear exceptions.
Requirements
- PHP 8.4 or newer.
- No additional runtime Composer dependencies.
Installation
composer require wilycode/dotenv
Quick start
Create a .env file in your application directory:
APP_NAME="My Website" APP_ENV=local APP_DEBUG=true FEATURE_ENABLED=false PORT=8081 RETRY_COUNT=3 RATE=1.32424 BASE_URL="http://localhost:${PORT}"
Load its values when your application starts:
<?php require __DIR__ . '/vendor/autoload.php'; use WilyCode\DotEnv\DotEnv; $dotenv = new DotEnv(__DIR__ . '/.env'); $loaded = $dotenv->load(); echo getenv('APP_ENV'); // local echo $loaded['BASE_URL']; // http://localhost:8081
load() returns only the variables that were actually written to the environment. An already-defined variable is not replaced unless you enable overwriting.
Read without loading
Use read() to parse a file without updating getenv(), $_ENV, or $_SERVER:
$values = (new DotEnv(__DIR__ . '/.env'))->read(); echo $values['APP_NAME']; // My Website
This is useful when you want to inspect or process configuration separately.
Booleans, numbers, and other values
All .env values are strings. DotEnv does not automatically convert them into PHP bool, int, float, null, arrays, or objects. For example:
APP_DEBUG=true FEATURE_ENABLED=false RETRY_COUNT=3 RATE=1.32424 OFFSET=-2.5 EMPTY_VALUE= OPTIONAL_VALUE=null
.env value |
Value returned by read() |
PHP type |
|---|---|---|
true |
"true" |
string |
false |
"false" |
string |
3 |
"3" |
string |
1.32424 |
"1.32424" |
string |
-2.5 |
"-2.5" |
string |
Empty value (KEY=) |
"" |
string |
null |
"null" |
string |
If you need typed values in your application, convert and validate them in PHP:
$values = (new DotEnv(__DIR__ . '/.env'))->read(); $debug = filter_var($values['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); $featureEnabled = filter_var($values['FEATURE_ENABLED'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); $retryCount = filter_var($values['RETRY_COUNT'], FILTER_VALIDATE_INT); $rateValue = $values['RATE']; if ($debug === null || $featureEnabled === null || $retryCount === false || !is_numeric($rateValue)) { throw new UnexpectedValueException('Invalid .env configuration value.'); } $rate = (float) $rateValue; // 1.32424
Use a dot as the decimal separator (1.32424, not 1,32424). Avoid (bool) $values['FEATURE_ENABLED'] — in PHP, the non-empty string "false" would become true. A literal null is not an empty or missing value; interpret it explicitly if your application needs nullable configuration. Arrays or objects can be stored as JSON strings and decoded by the application when needed.
Overwrite existing variables
By default, load() keeps values already present in the process environment:
$dotenv->load(); // Existing environment values win.
To replace them explicitly:
$dotenv->load(overwrite: true);
load() writes values to getenv(), $_ENV, and $_SERVER. It does not write changes back to the .env file.
Supported .env syntax
# A full-line comment export APP_MODE=development EMPTY_VALUE= PORT=8081 # Double quotes allow ${NAME} expansion and escapes such as \n and \t BASE_URL="http://localhost:${PORT}" MESSAGE="First line\nSecond line" # Single quotes keep the text literal LITERAL='${PORT} is not expanded' # Escape $ inside double quotes to keep a placeholder literal EXPANDED="${PORT}" ESCAPED="\${PORT}" # An inline comment starts after whitespace TIMEOUT=30 # seconds URL=https://example.test/#fragment
A few rules to remember:
- Names must contain letters, digits or underscores and cannot start with a digit.
- Values are always strings:
PORT=8081produces"8081",APP_DEBUG=falseproduces"false", andRATE=1.32424produces"1.32424". ${NAME}is expanded in unquoted and double-quoted values. An undefined name expands to an empty string.- In
read(), earlier entries in the file take precedence when expanding${NAME}; existing environment values are used as a fallback. - In
load(), existing environment values also take precedence during expansion unlessoverwrite: trueis specified. This keeps references consistent with the values that will actually be loaded. - Inside double quotes,
\${NAME}produces literal${NAME}, while${NAME}expands.\\${NAME}produces a backslash followed by the expanded value. - Single-quoted values are literal: no variable expansion.
- Invalid lines, missing
=, and unterminated quotes cause an exception.
For example, if the process already defines PORT=9000 and the file contains PORT=8081 followed by URL="http://localhost:${PORT}", then read()['URL'] is http://localhost:8081, while load()['URL'] is http://localhost:9000 by default. Passing overwrite: true uses 8081 instead.
Error handling
The constructor checks that the file exists. Parsing and loading can also fail:
use WilyCode\DotEnv\DotEnv; use WilyCode\DotEnv\Exception\DotEnvException; try { (new DotEnv(__DIR__ . '/.env'))->load(); } catch (DotEnvException $exception) { // Log or report the error in your application. error_log($exception->getMessage()); }
The exception types are:
| Exception | Meaning |
|---|---|
DotEnvFileNotFoundException |
The requested file does not exist. |
DotEnvFileNotReadableException |
The file cannot be read. |
DotEnvParseException |
A line is invalid or an environment variable cannot be set. |
All three extend DotEnvException.
Security
.env files may contain passwords and API keys. Keep them outside publicly served directories and never commit real secrets to Git. Add .env to your application's .gitignore and commit a safe .env.example instead.
Do not display or log the parsed values if they contain secrets. Use your hosting environment's secret management facilities for production deployments when available.
Development
composer install
composer validate --strict
composer test
Tests run automatically in GitHub Actions on pushes and pull requests. Tests are present in the Git repository but excluded from distribution archives.
Contributing
Issues and pull requests are welcome. See CONTRIBUTING.md and the issue tracker.
License
MIT © 2026 Simon Piter. See LICENSE.