drevops / environment-detector
Universal environment detector
Fund package maintenance!
alexskrypnyk
Patreon
Requires
- php: >=8.3
Requires (Dev)
- alexskrypnyk/phpunit-helpers: ^0.13.0
- dealerdirect/phpcodesniffer-composer-installer: ^1
- drupal/coder: ^8.3
- ergebnis/composer-normalize: ^2.42
- opis/closure: ^4.0
- phpbench/phpbench: ^1.4
- phpstan/phpstan: ^2
- phpunit/phpunit: ^12
- rector/rector: ^2
- skpr/config: ^3.0
README
Zero-config environment type detection
Features
- Detects environment type:
local
,ci
,dev
,preview
,stage
,prod
, or user-defined - Supports many popular providers out-of-the-box: Acquia, CircleCI, DDEV, Docker, GitHub Actions, GitLab CI, Lagoon, Lando, Pantheon, Platform.sh, Skpr, Tugboat
- Detects custom contexts: Drupal (more to come)
- Simple API for checking current environment
- Extendable via custom providers and contexts
- Override and fallback support for precise control
- Optimised for performance with static caching
Installation
composer require drevops/environment-detector
Quick Start
use DrevOps\EnvironmentDetector\Environment; Environment::init(); if (getenv('ENVIRONMENT_TYPE') === Environment::LOCAL) { // Apply local settings. }
Alternatively, use the convenience methods:
use DrevOps\EnvironmentDetector\Environment; // No need to init() - a first call to is*() will auto-initialize. if (Environment::isLocal()) { // Apply local settings. } if (Environment::isProd()) { // Apply production settings. }
How It Works
- Provider detection: Each provider checks for environment-specific variables or files to identify itself.
- Type mapping: Once identified, the provider maps its internal state to a
type like
dev
,prod
, or a custom type. - Context detection: Optionally applies provider- or framework-specific
changes (e.g., modify Drupal
$settings
global variable to add$settings['environment']
value).
The resolved type is stored in the ENVIRONMENT_TYPE
env var. If already set,
this value takes precedence over the provider detection. The contextualize
still applies context changes even if the type is pre-set via environment
variable.
Advanced Usage
Advanced initialization with customization
Environment::init( contextualize: TRUE, // Whether to apply the context automatically fallback: Environment::DEVELOPMENT, // The fallback environment type override: function($provider, $type) { // The override callback to change the environment type if ($type === Environment::DEVELOPMENT && $provider->id() === 'tugboat') { return 'qa'; } return $type; }, providers: [new MyCustomProvider()], // Additional provider instances contexts: [new MyCustomContext()], // Additional context instances );
Fallback Type
If an environment type is not detected, a fallback Environment::DEVELOPMENT
will be
returned by default. This is to ensure that, in case of misconfiguration, the application
does not apply local settings in production or production settings in local - 'development'
type is the safest default.
You can set a different fallback type during initialization:
Environment::init(fallback: Environment::PRODUCTION);
Providers
Only one provider can be active. If multiple match, or none match, an exception
is thrown. Register custom providers using init(providers:[MyCustomProvider::class])
.
Supported built-ins:
Accessing Provider Data
// Initialize first to detect the active provider Environment::init(); $provider = Environment::getActiveProvider(); if ($provider && $provider->id() === 'acquia') { // Acquia-specific logic $data = $provider->data(); if (isset($data['AH_SITE_GROUP'])) { // Use Acquia-specific environment data } }
Adding a Custom Provider
use DrevOps\EnvironmentDetector\Providers\ProviderInterface; use DrevOps\EnvironmentDetector\Environment; class CustomHosting implements ProviderInterface { public function active(): bool { return isset($_SERVER['CUSTOM_ENV']); } public function data(): array { return ['CUSTOM_ENV' => $_SERVER['CUSTOM_ENV'] ?? null]; } public function type(): ?string { return match ($_SERVER['CUSTOM_ENV_TYPE'] ?? null) { 'dev' => Environment::DEVELOPMENT, 'qa' => 'qa', 'live' => Environment::PRODUCTION, default => null, }; } public function id(): string { return 'customhosting'; } public function label(): string { return 'Custom Hosting'; } public function contextualize(\DrevOps\EnvironmentDetector\Contexts\ContextInterface $context): void { // Optional: Apply provider-specific context changes } } // Register the custom provider during initialization Environment::init(providers: [new CustomHosting()]);
Contexts
Contexts apply environment-specific changes to frameworks or applications. A context may provide generic changes that are applied to the application. A provider may also provide provider-specific context changes.
For example, a Drupal context applies changes to the global $settings
array, while a
Lagoon provider's contextualize()
method adds Lagoon-specific changes to the $settings
array.
The goal is to have enough context changes to cover the most common use cases, but also to allow adding custom contexts to cover specific use cases within the application.
Adding a custom context
use DrevOps\EnvironmentDetector\Contexts\ContextInterface; class CustomContext implements ContextInterface { public function active(): bool { return class_exists('MyFramework'); } public function contextualize(): void { // Apply generic context changes global $configuration; $configuration['custom_value'] = $_SERVER['custom_value'] ?? 'default'; } public function id(): string { return 'myframework'; } public function label(): string { return 'My Framework'; } } // Register the custom context during initialization Environment::init(contexts: [new CustomContext()]);
Maintenance
composer install
composer lint
composer test
This repository was created using the Scaffold project template.