This package provides interoperable interfaces to load and parse environment files, and encapsulate environment variables, in PHP 8.4 or later. It reflects, refines, and reconciles the common practices identified within several pre-existing projects.
The standards provided in this package are also informed by:
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174).
This package defines the following interfaces:
-
EnvLoaderService affords loading environment variables parsed from an environment file into
$_ENV(and possibly elsewhere). -
EnvParserService affords parsing a string for environment variables.
-
EnvSetterService affords modifying an environment variable in
$_ENV(and possibly elsewhere). -
EnvGetter affords getting environment variable values.
-
EnvThrowable interface extends Throwable to mark an Exception as environment-related.
-
EnvTypeAliases provides PHPStan type aliases to aid static analysis.
The EnvLoaderService interface affords setting environment variables
parsed from an environment file into $_ENV (and possibly elsewhere).
-
Notes:
-
This is not a general-purpose configuration utility. Instead, it is specifically for settings that change depending on the deployment environment.
-
No environment file name is specified. Typically, the file name will be
.env, but consumers can specify any file name they like. -
No environment file format is specified. Implementations might load from DotEnv, INI, JSON, XML, PHP, or any other environment file format.
-
Only
$_ENVloading is required. Cf. the EnvSetterService interface notes.
-
-
public function loadEnv(string $filename, bool $override = false) : static;
-
Loads environment variables into
$_ENV(and possibly elsewhere) as parsed from an environment file that exists and is readable. -
Directives:
-
Implementations MUST throw EnvThrowable if the
$filenamedoes not exist, is not a file, is not readable, or if reading from the$filenamefails. -
Implementations MUST parse the contents of
$filenamefor environment variables using the EnvParserService methodparseEnv(). -
Implementations MUST process each parsed environment variable using the EnvSetterService method
setEnv(). -
Implementations MUST return
$this.
-
-
Notes:
- This method is fluent. Returning
$thisallows consumers to load multiple files in sequence.
- This method is fluent. Returning
-
-
public function loadEnvIfExists( string $filename, bool $override = false, ) : static;
-
An alias to
loadEnv()that loads an environment file only if it exists. -
Directives:
-
Implementations MUST NOT attempt to load
$filenameif it does not exist or is not a file; otherwise, implementations MUST behave as ifloadEnv()was called with the same arguments. -
Implementations MUST return
$this.
-
-
Notes:
-
Sometimes an environment file is optional. For example, one strategy is to have a
.envonly in development, but not in production. Another is to have a base.envfile as well as an optional deployment-specific environment file. This method allows that the non-existence of a file is not an error. -
This method is fluent. Returning
$thisallows consumers to load multiple files in sequence.
-
-
-
public function assertEnv(array $names = []) : void;
-
Asserts that each of the environment variable
$nameshas been set into$_ENV(and possibly elsewhere). -
Directives:
-
Implementations MUST throw EnvThrowable if
$_ENVis not set for one or more of the environment variable$names. -
Implementations SHOULD throw EnvThrowable if one or more of of the environment variable
$namesis not present in other environment vairable locations.
-
-
Notes:
-
Only
$_ENVchecking is required. Implementations might additionally check other locations, such asgetenv()orapache_setenv(). -
This method is not fluent. Whereas the loading methods return
$thisso that additional loading can continue, asserting that all expected variables are set is to be done only after all loading is complete.
-
-
The EnvParserService interface affords parsing a string for environment variables.
-
Notes:
- No environment string syntax is specified. Implementations may parse DotEnv, INI, JSON, XML, PHP, or any other syntax.
-
public function parseEnv(string $contents) : env_parsed_array;
-
Parses the
$contentsto return an array of environment variables. -
Directives:
-
Implementations MUST throw EnvThrowable if parsing fails.
-
Implementations MAY validate the parsed variables; implementations doing so MUST throw EnvThrowable on invalidity.
-
Implementations MAY sanitize, normalize, transform, or otherwise modify the parsed variables.
-
-
The EnvSetterService interface affords modifying an environment
variable in $_ENV (and possibly elsewhere).
-
Notes:
- Only
$_ENVmodification is required. Implementations might also choose to modify other environment variable locations such as$_SERVER,putenv(),apache_setenv(),define(), and so on.
- Only
-
public function setEnv( string $name, string|int|float|bool|null $value, bool $override = false, ) : void;
-
Modifies
$_ENVand possibly other environment variable locations. -
Directives:
-
Implementations MUST examine
$_ENV[$name]; when doing so ...-
Implementations MUST NOT modify
$_ENV[$name]when it is already set and$overrideis false. -
Implementations MUST unset
$_ENV[$name]when the$valueisnull. -
Implementations MUST set
$_ENV[$name]to string0when the$valueis booleanfalse. -
Implementations MUST set
$_ENV[$name]to string1when the$valueis booleantrue. -
Implementations MUST set
$_ENV[$name]to a(string)cast of the$valuein all other cases.
-
-
Implementations MAY examine other environment variable locations; when doing so ...
-
Implementations MUST NOT modify a colliding environment variable
$namewhen$overrideis false. -
Implementations SHOULD otherwise modify the environment variable
$nameas appropriate for that environment location.
-
-
-
Notes:
-
String representations of
null,false, and empty-string can be easy to confuse. The rules specified above guarantee that a missing environment variable representsnull, that a string0representsfalse, and that an empty string is just that: an empty string. (Consumers may still cast these string values as desired.) -
Set or unset environment variables in non-
$_ENVlocations as desired. Some implementations might additionally modify the$_SERVERarray, some might set them usingputenv(), some mightdefine()them as constants, and so on.
-
-
The EnvGetter interface affords getting environment variable values.
-
Directives:
- Implementations SHOULD treat this as an interface to a value object, but MAY treat it as a global values reader.
-
Notes:
-
Prefer copying environment variables into the implementation. For example, copy
$_ENVorgetenv()into a property, then retrieve values from that property. However, some implementations may find it necessary to read from the global environment directly. -
Consider placing environment validation logic in the constructor. Value objects are expected to self-validate, so checking for missing or improperly-formatted environment variables is a normal behavior here.
-
-
public function getEnv(string $name) : ?string;
- Returns the
$nameenvironment variable value as a string, ornullif it is not set in the environment.
- Returns the
The EnvThrowable interface extends Throwable to mark an Exception as environment-related. It adds no class members.
The EnvTypeAliases interface provides PHPStan type aliases to aid static analysis.
-
env_parsed_array array<string,null|bool|int|float|string>- An
arrayof variable names and values as parsed from the contents of an environment file.
- An
-
Directives:
- Implementations MAY define additional class members not defined in these interfaces.
-
Notes:
- Reference implementations may be found at https://github.com/env-interop/impl.
Environment configuration is specific to the deployment and not to the application. This nuance means a general-purpose configuration system would have to be constrained specifically to suit the purpose of declaring environment variables. Cf. https://12factor.net/config:
An app's config is everything that is likely to vary between deploys (staging, production, developer environments, etc).
...
Note that this definition of "config" does not include internal application config, such as config/routes.rb in Rails, or how code modules are connected in Spring. This type of config does not vary between deploys, and so is best done in the code.
Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard.
With all that in mind, Env-Interop defines standard interfaces around the constraints of deployment-specific, not general-purpose, configuration.
Of the researched projects, a minority check to see if required environment variables are set. Of those, only one does any further validation of the environment variable values themselves.
The "required to be set" validation is provided by the EnvLoaderService
method assertEnv(). Env-Interop advises that any further environment value
validation is the responsibility of an EnvParserService or of an
EnvGetter value object.