Laravel中env函数的坑
不自量力的还手 直至死方休
最近项目中遇到了一个问题, 问题出在env函数上,在Middleware中读取环境变量时取到的竟然是null
1 | dump(env('APP_ENV') === null); // true |
查看env 的代码
1 | function env($key, $default = null) |
可以发现,实际上调用的就是php自带的getenv
函数,如果取不到值,那必定是某段执行putenv或者操作$_ENV
全局变量的代码没有执行,而且这些环境变量设置操作一定是在初始化的时候进行的
如果对Laravel的Kernel执行顺序比较了解的话,应该知道,在Kernel启动阶段会首先执行一组bootstrappers
1 | //Illuminate/Foundation/Http/Kernel.php |
其中一个bootstrapper名为DetectEnvironment,而它的嫌疑是最大的,检查这个类
1 | //Illuminate/Foundation/Bootstrap/DetectEnvironment.php |
在代码中,我们并没有发现任何执行putenv或者操作$_ENV
全局变量的地方,实际上在整个Laravel的框架代码里也没有发现蛛丝马迹,那么这些环境变量是如何保存进来的呢?
如果Laravel框架里没有执行这些代码,我们应该可以推测是框架使用的第三方组件做了这些事情
而事实也确实如此,可以看到在DetectEnvironment类的bootstrap方法里实例化了一个Dotenv类的对象,而Dotenv\Loader正是执行了读取.env文件,执行putenv的操作。
那么env获取不到值只能说明Dotenv的实例化并没有执行
再仔细看一下DetectEnvironment类,在实例化Dotenv前,先进行了一个 if 判断
1 | if (! $app->configurationIsCached()) |
而这个方法的作用就是判断 bootstrap/cache/config.php
缓存文件是否存在,如果文件存在则不会执行Dotenv的实例化操作,也就不会往$_ENV
里存数据,自然env函数是取不到值的
bootstrap/cache/config.php
是执行下面的命令生成的
1 | php artisan config:cache |
清除使用命令
1 | php artisan config:clear |
那么,真相大白了,之前在开发时并没有出现问题,是因为没有执行 config:cache 命令,而项目上线后为了优化访问速度,生成了缓存文件,导致env取值失败
如果使用了config:cache,env函数只能在config目录下的配置文件的php里使用,不可以在其他地方使用。
一个非常简单的办法就是将
1 | env('APP_ENV') |
改为
1 | config('app.env') |
config函数会优先读取 bootstrap/cache/config.php 中缓存的配置,如果没有缓存文件,则会直接读取 config 目录下的所有配置文件