Environment Contracts

The Environment package has no interface layer, but it does have a few strong code-level contracts.

Load-before-read contract

Environment::getValue() throws EnvException::environmentNotLoaded() until load() has completed.

That means this is invalid:

$value = env('APP_NAME');

unless the application bootstrap has already loaded the environment.

hasKey() and getRow() do not enforce the same guard. They read directly from the internal cache and simply behave as if the store is empty before load.

One-shot load contract

Environment::load() returns immediately when $loaded is already true.

This is not a reload API. It is a first-load-only initializer.

File existence contract

After choosing the target file name, Environment::load() checks file_exists(...) on App::getBaseDir() . DS . $envFile.

If the file is missing, it throws EnvException::fileNotFound($this->envFile).

The package does not silently skip missing environment files.

Mutability contract

updateRow() requires two preconditions:

  • setMutable(true) must have been called
  • the environment must already be loaded

If mutability is off, the method throws EnvException::environmentImmutable().

If loading has not happened yet, it throws EnvException::environmentNotLoaded().

Environment-name contract

The environment predicate helpers are exact string comparisons:

  • isProduction() checks for production
  • isStaging() checks for staging
  • isDevelopment() checks for development
  • isTesting() checks for testing
  • isLocal() checks for local

Any other app_env string is still accepted by load(), but all five helpers return false.

Server accessor contracts

Server exposes convenience methods with fixed precedence and normalization rules.

Protocol detection

protocol() returns https when either of these is true:

  • HTTPS is present and not equal to off after lowercasing
  • SERVER_PORT == 443

Otherwise it returns http.

Content type parsing

contentType() returns raw CONTENT_TYPE by default.

contentType(true) strips everything after the first ;, so:

application/json; charset=UTF-8

becomes:

application/json

AJAX detection

ajax() returns true only when HTTP_X_REQUESTED_WITH, after lowercasing, is exactly xmlhttprequest.

IP precedence

ip() resolves the first non-null value in this order:

  1. HTTP_CLIENT_IP
  2. HTTP_X_FORWARDED_FOR
  3. REMOTE_ADDR

This is a simple precedence check. The method does not parse forwarded IP lists and does not validate trusted proxies.

Accepted language parsing

acceptedLang() takes the first comma-separated entry from HTTP_ACCEPT_LANGUAGE, trims it, then returns the first two lowercase characters.

Examples:

  • en-US,en;q=0.9 -> en
  • fr -> fr

Error contract

The package defines two local exception factories in EnvException:

  • environmentImmutable()
  • environmentNotLoaded()

It also calls fileNotFound(...), inherited from the shared base exception layer, when the selected .env file is absent.