🐷

Laravelのenvの設定処理はどうなっているのか

2024/01/06に公開

途中までしか書けてませんが、必要なことは書いてるので一旦公開します。

面倒な人向けのまとめ

  1. キャッシュされた設定があるならそれが優先的にロードされ、以降の処理はされない。
  2. APP_ENV環境変数があるかを確認する
  3. .envファイル(APP_ENV環境変数があって該当ファイルが存在する場合は.env.環境名ファイル)を読み込む

注意点

  • 環境変数の値のほうが優先です。($_ENVで、すでにロードされている)
  • 勘違いされがちですが、.env.環境名.env両方が読み込まれると言ったことはありません。
  • config:cacheでキャッシュすると.envをロードしなくなるのでenv関数をconfig以外で使うのはNG。

実際のコードを見ていく

まず、EnvをロードしようとするのはKernel.phpbootstrappersにあるLoadEnvironmentVariablesです。

protected $bootstrappers = [
    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
    \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
    \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
    \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
    \Illuminate\Foundation\Bootstrap\BootProviders::class,
];

LoadEnvironmentVariablesの処理

public function bootstrap(Application $app)
{
    if ($app->configurationIsCached()) {
        return;
    }

    $this->checkForSpecificEnvironmentFile($app);

    try {
        $this->createDotenv($app)->safeLoad();
    } catch (InvalidFileException $e) {
        $this->writeErrorAndDie($e);
    }
}

$app->configurationIsCached()

cache/config.phpの中身があるかをチェックします。
これはphp artisan config:cacheを利用した場合に設定類をキャッシュするのでこのキャッシュファイルがある場合はこのLoadEnvironmentVariablesの処理はされません。

$this->checkForSpecificEnvironmentFile($app)

対象の処理は以下です。

protected function checkForSpecificEnvironmentFile($app)
{
    if ($app->runningInConsole() &&
        ($input = new ArgvInput)->hasParameterOption('--env') &&
        $this->setEnvironmentFilePath($app, $app->environmentFile().'.'.$input->getParameterOption('--env'))) {
        return;
    }

    $environment = Env::get('APP_ENV');

    if (! $environment) {
        return;
    }

    $this->setEnvironmentFilePath(
        $app, $app->environmentFile().'.'.$environment
    );
}

この処理を見てみると、アプリケーションの環境情報を取得できた場合に$this->setEnvironmentFilePathでenvファイルの名前を登録しています。

Env::get('APP_ENV')が一番悩ましい部分ですが、ここではまだ.envファイルのロードはされていないので環境変数としてAPP_ENVが定義されている場合にのみ存在するということになります。

一番わかりやすい例としてはテストで、phpunit.xmlに記述する<env name="APP_ENV" value="testing" force="true"/>とか、テスト用DBにマイグレーションを実施するためにphp artisan migrate --env=testingとかがここに引っかかることになります。

ここでは環境名をくっつけるようにしているので、APP_ENVtestingだと、.env.testingをロードする予定のファイル名としているわけです。

なお、setEnvironmentFilePathの処理に該当ファイルが存在しているかのチェックがあるので、該当ファイルがない場合は.envが読まれることになります。

$this->createDotenv($app)->safeLoad()

protected function createDotenv($app)
{
    return Dotenv::create(
        Env::getRepository(),
        $app->environmentPath(),
        $app->environmentFile()
    );
}

理解に悩むのがEnv::getRepository()です。
ちょっとこの辺り複雑な感じだったので、後ほど頑張って書こうと思います。。。

Discussion