dotenv 在生产环境中需要 .env 文件

dotenv requires .env file on production

我正在为 PHP 使用 dotenv 来管理环境设置(不是 lavarel,但我标记了它,因为 lavarel 也使用 dotenv)

我已将 .env 从代码库中排除,并为所有其他协作者添加了 .env.example

在 dotenv 的 github 页面上:

phpdotenv is made for development environments, and generally should not be used in production. In production, the actual environment variables should be set so that there is no overhead of loading the .env file on each request. This can be achieved via an automated deployment process with tools like Vagrant, chef, or Puppet, or can be set manually with cloud hosts like Pagodabox and Heroku.

我不明白的是我收到以下异常:

PHP Fatal error: Uncaught exception 'InvalidArgumentException' with message 'Dotenv: Environment file .env not found or not readable.

这与文档中所说的相矛盾"the actual environment variables should be set so that there is no overhead of loading the .env file on each request."

所以问题是 dotenv 抛出该异常是否有任何原因 and/or 我是否遗漏了什么?首先,与其他 dotenv 库相比,行为是不同的 (ruby)

我可以轻松解决这个问题,不太好的解决方案:

if(getenv('APPLICATION_ENV') !== 'production') { /* or staging */
    $dotenv = new Dotenv\Dotenv(__DIR__);
    $dotenv->load();
}

我认为最好的解决方案,但我认为 dotenv 应该处理这个问题。

$dotenv = new Dotenv\Dotenv(__DIR__);
//Check if file exists the same way as dotenv does it
//See classes DotEnv\DotEnv and DotEnv\Loader
//$filePath = $dotenv->getFilePath(__DIR__); 
//This method is protected so extract code from method (see below)

$filePath = rtrim(__DIR__, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR . '.env';
//both calls are cached so (almost) no performance loss
if(is_file($filePath) && is_readable($filePath)) {
    $dotenv->load();
}

Dotenv 是围绕一个想法构建的,即它将仅用于开发环境。因此,它总是期望 .env 文件存在。

您不喜欢的解决方案是使用 Dotenv 的推荐方式。看起来,它 won't change in near future. Related discussion in project's issue tracker: https://github.com/vlucas/phpdotenv/issues/63#issuecomment-74561880

请注意,Mark offers 有一个适用于 production/staging 环境的好方法,它会跳过文件加载,但不会跳过验证

$dotenv = new Dotenv\Dotenv();
if(getenv('APP_ENV') === 'development') {
    $dotenv->load(__DIR__);
}
$dotenv->required('OTHER_VAR');

如果您在创建 APP_ENV 变量时遇到问题,此代码更简单:

$dotenv = new Dotenv\Dotenv(__DIR__);
if(file_exists(".env")) {
    $dotenv->load();
}

也调查了这个,我目前的解决方案是使用 Lumen's way (as of 6 June 2016) which was suggested in a discussion:

try {
    (new Dotenv\Dotenv(__DIR__.'/../'))->load();
} catch (Dotenv\Exception\InvalidPathException $e) {
    //
}

如果需要,您仍然可以进行一些额外的异常处理(例如,恢复为默认值或进行一些验证。