Laravel 环境变量(方法中没有传递默认值)在 Artisan 命令文件中不起作用

Laravel Environment Variables(without default value passed in method) not working inside Artisan Command file

我正在为客户的项目使用 Laravel 6.x,其中我在 Artisan Command 中构建了一个 API 用于同步数据。

现在客户希望配置谨慎,脱离主要源代码并且尽可能没有任何回退值。这意味着我必须在 .env 文件中定义配置并使用没有任何后备默认值的 env() 方法。

这在 Laravel Artisan 命令 class 文件中必须是可能的,但是当我在代码中使用 env 方法时它没有按预期工作,如下所示:

[siteroot]\.env:

APP_ENV=local

[siteroot]\app\Console\Commands\SyncSomeData.php:

use Illuminate\Console\Command;

class SyncSomeData extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'sync:some-data';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        exit(env('APP_ENV','staging1'));
    }
}

这总是在控制台中打印 staging1,如果我使用它而不是给定的 env 方法,那么它什么都不打印:

exit(env('APP_ENV'));

据我所知并且可以相信 Laravel 是最安全的,必须有办法让 env 方法在命令文件中没有回退值的情况下工作,任何人都可以帮助完成这个吗?

这个答案有几个部分。

  1. 缓存配置

仅当您在本地环境中缓存配置时才会出现此问题中的问题。如果您曾经 运行 php artisan config:cachephp artisan optimize,那么您已经缓存了您的配置。

因此,laravel 将不再读取您的 .env 文件并从缓存中加载配置和 .env 的所有值。

最好不要在整个应用程序中使用 env(),而是为这些值创建配置文件。这将 speed up your application in production。如果你想利用配置缓存,除了在你的配置文件中,你不能在任何地方使用 env()。

在您的本地环境中,文档建议您不要缓存您的配置,因为它会经常更新。我认为这是一个很好的建议,但有一个警告:env()。如果您没有在本地缓存您的配置,而是在生产环境中,您将不会遇到像在本地引发此 post 的错误。如果您有 ci 管道和良好的测试实践,那么这个障碍就可以克服。

如果您坚持使用本地缓存配置,每次更新配置文件或 .env 文件时都需要 运行 php artisan config:cache.

  1. 禁用配置缓存

通过 运行 宁 php artisan config:clear 或删除 /bootstrap/cache/config.php laravel 将不再尝试从缓存中读取配置,并且 .env 将在配置文件之外工作。如果你这样做,正如我在 (1) 中所述,如果你在生产中缓存配置,请确保你的管道的一部分会捕获这些错误。

经过与OP的更多讨论,我再澄清一件事:

缓存配置不会自动缓存您的 .env 密钥,因此您可以像配置一样访问它们('SOME_CUSTOM_DOT_ENV_KEY')。使用缓存配置时,如果您需要访问应用程序内部的环境变量,则必须在配置文件中引用它们。

同样,一旦启用配置缓存,.env 就没用了,但它用于构建缓存。

所以如果你在 .env 中说:

GOOGLE_API_TOKEN=xxxx

您可能会创建一个配置文件,例如:

google.php

return [
    'api_token' => env('GOOGLE_API_TOKEN', 'some-default-value'),
];

并且在您的应用程序中,您只会引用 config('google.api_token') 而不会引用 env('GOOGLE_API_TOKEN').