In a PHP project, what does a .env loader do, and should production read its database credentials from a .env file?
answer
- PHP never reads .env on its own
- copies values into $_ENV/$_SERVER
- commit .env.example, not .env
- real variables usually win over the file
- production: variables set by the platform
basics
~20 sPHP never reads .env files; a loader library parses one at boot and copies the values into $_ENV/$_SERVER, optionally putenv(). It suits local development; production sets real environment variables, and a .env with secrets is never committed.
solid answer
~40 sA `.env` file is a list of `NAME=value` lines. PHP itself ignores it; a Composer package such as `vlucas/phpdotenv` or `symfony/dotenv` parses it early in the bootstrap and writes each value into `$_ENV` and `$_SERVER`, and in some configurations into the process environment through `putenv()`. Which store it writes to decides whether `getenv()` can see the values, so read through the same path the loader fills. Loaders are typically configured not to override variables that already exist, so a value set by the platform wins over the file. In development that gives each developer local credentials; in production the platform should set real environment variables or mount secret files. The `.env` holding secrets stays out of version control; you commit a `.env.example` with names and dummy values.
code
bash · 5 lines# .env.example (committed): names and placeholders only
APP_ENV=local
DB_HOST=127.0.0.1
DB_USER=app
DB_PASSWORD=change-mego deeper
Recall that PHP does not read .env by itself, that a loader package does it, and that .env is git-ignored while .env.example is committed.
Explain which stores a loader writes to, why getenv() can miss those values, and why real environment variables take precedence over the file.
Keep production independent of hand-edited .env files: platform-set variables or secret files, boot-time validation of required names, and safe handling of an accidentally deployed file.
Choose the configuration contract for all services — environment names, secret delivery, rotation — so staging and production differ only in values injected by the platform.
## What a `.env` file is A `.env` file is a plain-text file in the project root with one setting per line: ``` APP_ENV=local DB_HOST=127.0.0.1 DB_PASSWORD="local-only-password" ``` It is a convention, not a PHP feature. **PHP never reads `.env` on its own** — no directive, no SAPI and no function loads it. A value there is invisible to your code until something parses it. ## What a loader does Loader libraries installed with Composer — `vlucas/phpdotenv` and `symfony/dotenv` are the common ones — run early in the bootstrap, usually from the front controller or the console entry point: 1. find and read the file (and sometimes environment-specific variants); 2. parse each line, handling quotes, comments and references to other variables; 3. skip names that already exist in the real environment, in their default configuration; 4. write the values into one or more stores: `$_ENV`, `$_SERVER`, and — depending on the library and how it is configured — the process environment via `putenv()`. Step 4 is the source of a classic confusion. If the loader writes only to `$_ENV`/`$_SERVER`, then `getenv('DB_HOST')` returns `false` while `$_ENV['DB_HOST']` works. Check which stores your loader fills and read configuration through the same path everywhere. ## Precedence: real variables win Because step 3 skips existing variables by default, a value set by the operating system, container or process manager overrides the file. This is deliberate: - a developer can keep a `.env` with local defaults; - CI or production sets real variables that take precedence without editing any file; - a stray `.env` accidentally deployed does not silently replace production settings, as long as production sets every variable. ## Development versus production | Concern | Local development | Production | |---|---|---| | Source of values | `.env` parsed by the loader | variables set by the platform, or secret files | | Who can see secrets | the developer | only the deployment system and the running process | | Cost | parsing a file on every request or command | none — the environment is already there | | Risk | a committed `.env` leaks secrets | a `.env` in the document root is downloadable | Some frameworks go further for production and compile the resolved values into a cached PHP file, so no `.env` parsing happens per request. The common thread is that production does not depend on a hand-edited `.env` on the server. ## Version control rules - Add `.env` to `.gitignore`: it holds real secrets for one machine. - Commit `.env.example` (or `.env.dist`) with every variable name and harmless placeholder values, so a new developer knows what to set. - Never place `.env` inside the web server's document root; a request for `/.env` would return it as text. - Rotate any credential that was ever committed, even if the commit was later removed — history keeps it. ## Per-environment database credentials For the common case of separate staging and production databases: - both environments read the same names — `DB_HOST`, `DB_USER`, `DB_PASSWORD` — so code never branches on the environment name to pick credentials; - staging's platform sets staging's values and production's platform sets production's, so no file contains both; - the application validates at boot that each required variable is present and fails fast with the variable's name (never its value) in the message. ## Why not just commit a config file per environment? A committed `config/production.php` with the real password puts the secret in every clone, every CI log that prints files, and every backup of the repository. Keeping the structure in code and the secret in the environment — or a mounted secret file — narrows who can read it to the machines that run the application.
- After adding a .env loader, $_ENV['DB_HOST'] works but getenv('DB_HOST') returns false. Why?The loader wrote the values into `$_ENV` and `$_SERVER` but not into the process environment, which is the only thing `getenv()` reads. Many loaders only call `putenv()` when configured to, because the process environment is shared and not thread-safe. Read configuration through the store the loader fills, or enable its `putenv()` option knowingly.
- A deploy copies the developer's .env to the production server by mistake. What limits the damage?Loaders by default do not override variables that already exist, so if production's platform sets every required variable, the stray file changes nothing. The file must still be removed and must never sit in the document root, where `/.env` would be downloadable.
saying these in an interview costs you the question
- PHP reads the .env file automatically when the script starts
- The .env file with real passwords should be committed so deploys are reproducible
- Values from .env always override variables set by the operating system
- Every .env loader makes values visible to getenv()
- Keeping .env in the public web directory is fine because it is not a PHP file