Laravelをお使いのみなさんは.envで環境変数を設定しているかと思いますが、もちろんサーバーの環境変数や実行時にコマンドで環境変数を指定することも可能です。
さて、.envとサーバー環境変数で同じキーを指定した場合にLaravelはどちらの値を優先するか、という記事です。
Laravelでの環境変数
Laravelではphpdotenvというライブラリを利用して環境変数を取得しています。
https://github.com/vlucas/phpdotenv
以下で各種Adapterが登録されます。
※Laravel v7系
※phpdotenv v4系
public static function getRepository()
{
if (static::$repository === null) {
$adapters = array_merge(
[new EnvConstAdapter, new ServerConstAdapter],
static::$putenv ? [new PutenvAdapter] : []
);
static::$repository = RepositoryBuilder::create()
->withReaders($adapters)
->withWriters($adapters)
->immutable()
->make();
}
return static::$repository;
}
ここでEnvConstAdapter
,ServerConstAdapter
,PutenvAdapter
の順に登録しています。
Adapter
先程登録されていた各種Adapterは以下のような仕組みになっています。
EnvConstAdapter
PHPのスーパーグローバル変数$_ENV
から値の取得・登録をします。
$_ENV
は現在のスクリプトに渡された環境変数を取得します。
ServerConstAdapter
PHPのスーパーグローバル変数$_SERVER
から値の取得・登録をします。
$_SERVER
はサーバーに定義された環境変数を取得します。
PutenvAdapter
PHPの組み込み関数getenv
とputenv
を利用して値の取得・登録をします。
環境変数の取得
env('string')
が呼び出される先は以下のように先程登録したAdapterを順に参照して、定義されている場合に値を返します。
定義がなければnullが返されます。
protected function getInternal($name)
{
foreach ($this->readers as $reader) {
$result = $reader->get($name);
if ($result->isDefined()) {
return $result->get();
}
}
return null;
}
結局優先順位はどうなってるの?
.envファイルが登録される際の挙動を見るとわかります。
public function set($name, $value = null)
{
if (!is_string($name)) {
throw new InvalidArgumentException('Expected name to be a string.');
}
// Don't overwrite existing environment variables if we're immutable
// Ruby's dotenv does this with `ENV[key] ||= value`.
if ($this->immutable && $this->get($name) !== null && $this->loaded->get($name)->isEmpty()) {
return;
}
$this->setInternal($name, $value);
$this->loaded->set($name, '');
}
ここのガート節で
if ($this->immutable && $this->get($name) !== null && $this->loaded->get($name)->isEmpty()) {
return;
}
とありますね。
つまり、EnvConstAdapter
,ServerConstAdapter
,PutenvAdapter
のどれらにも未定義の場合は値を新たに追加しています。
なので優先される値は
- 実行時の環境変数
- サーバー環境変数
- .envファイルの変数
になるかと思います。(違ったらご指摘ください)