Help us understand the problem. What is going on with this article?

env()はconfigファイル内でしか使えない

なぜか何度説明しても納得しない人が多い。

ドキュメント

日本語訳だと若干分かりにくい。

Note: 開発期間中にconfig:cacheコマンドを実行する場合は、設定ファイルの中で必ずenv関数だけを使用してください。設定ファイルがキャッシュされると、.envファイルはロードされなくなり、env関数の呼び出しは全てnullを返します。

https://readouble.com/laravel/5.8/ja/helpers.html#method-env

If you execute the config:cache command during your deployment process, you should be sure that you are only calling the env function from within your configuration files. Once the configuration has been cached, the .env file will not be loaded and all calls to the env function will return null.

https://laravel.com/docs/5.8/helpers#method-env

deploymentが「開発」になってるのでそもそも誤訳か。

本来はデプロイ、つまり本番環境でphp artisan config:cacheコマンドを使って最適化するならenv()はconfigファイルでしか使えない。config:cache後はenv()はnullしか返さないから。開発時でもconfig:cacheすれば同じだけど。

config:cacheしないなら使ってもいいけどドキュメントではすべきとなっている。
https://readouble.com/laravel/5.8/ja/deployment.html#optimizing-configuration-loading
https://laravel.com/docs/5.8/deployment#optimizing-configuration-loading
ここでもまたenv()に関する注意。知らずにconfig:cacheしたら100%アプリは壊れるのでしつこく注意。

良いとか悪いとか好みとか一切関係なくこれがLaravelのルールなので従う以外にない。

実際に動かして試す

Route::get('env', function () {
    dd(env('APP_ENV'));
});

cacheしてない→local

cacheしている→null

フレームワークの中身を確認

キャッシュファイルが存在すればここで読み込んでるのは分かる。

// First we will see if we have a cache configuration file. If we do, we'll load
// the configuration items from that file so that it is very quick. Otherwise
// we will need to spin through every configuration file and load them all.
if (file_exists($cached = $app->getCachedConfigPath())) {
    $items = require $cached;
    $loadedFromCache = true;
}

https://github.com/laravel/framework/blob/9fb420cc29a7dd5de5051f09c523ffc3ea01b969/src/Illuminate/Foundation/Bootstrap/LoadConfiguration.php#L27

env()でnullになるのはどこなのかは少し探しただけでは分からなかった。

ここですぐreturnされて何も読み込まれてないからかな。

if ($app->configurationIsCached()) {
    return;
}

https://github.com/laravel/framework/blob/9fb420cc29a7dd5de5051f09c523ffc3ea01b969/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php

この先はLaravel外パッケージの調査が必要。

他のパッケージのenv()と競合したら

滅多にないけどenv()はグローバル関数なので他のパッケージにenv()が含まれていたら競合して壊れることがある。
例えば。
https://github.com/cakephp/core/blob/f9d9823439e3c82fdb3f69d2c9210bab67e721af/functions.php#L189

Laravelでcakeのパッケージなんてインストールしないと思うだろうけど
自分でインストールしなくても何かのパッケージの依存先でインストールされるかもしれない。
知らない内に競合してると気付かないので怖い。

対策はインストールされないようにcomposer.jsonのconflictで指定するしかない。これが必須なパッケージだったらインストールしないせいで壊れるのでどうしようもない。

"conflict": {
    "cakephp/core": "*"
},

この対策としてLaravel 5.9でIlluminate\Support\Envが追加されるはずなのでグローバルなenv()を使わない回避手段ができる。
実際使うとなると全configファイルを修正なので面倒だけど。かなり特殊な用途なので仕方ない。

use Illuminate\Support\Env;

Env::get('APP_ENV');

宣伝?

最近はLaravelプロジェクトの手伝いも増えてるけど企業で使っててもこんな基礎的なことも分かってないことが多い。
Laravel製サイト見かける度にちょっと自分に直させてくれ…と思うことが多いので依頼したい人がいたらTwitterでもなんでもいいのでどこかから連絡して欲しい。
一プロジェクト辺りの対応時間は短めで複数のプロジェクトを改善したい。
「使うのはGitHubとSlack/Discordのみ。」の条件を満たせる場合のみ。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away