laravel 解析env()取值

.env 配置

APP_ENV=local

读取

echo env('APP_ENV');exit;
# sjx

为什么会读取不一致呢?

研究下env 执行流程

  1. 查看env 函数代码
    /**
     * Gets the value of an environment variable.
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    function env($key, $default = null)
    {
        $value = getenv($key);

        if ($value === false) {
            return value($default);
        }
		// 省略部分代码 ...
        return $value;
    }

可以发现,实际上调用的就是php自带的getenv函数,如果取不到值,那必定是某段执行putenv或者操作$_ENV全局变量的代码没有执行,而且这些环境变量设置操作一定是在初始化的时候进行的

如果对Laravel的Kernel执行顺序比较了解的话,应该知道,在Kernel启动阶段会首先执行一组bootstrappers


    /**
     * The bootstrap classes for the application.
     *
     * @var array
     */
    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 文件

    /**
     * Bootstrap the given application.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        if ($app->configurationIsCached()) {
            return;
        }

        $this->checkForSpecificEnvironmentFile($app);

        try {
            (new Dotenv($app->environmentPath(), $app->environmentFile()))->load();
        } catch (InvalidPathException $e) {
            //
        }
    }

在代码中,我们并没有发现任何执行putenv或者操作$_ENV全局变量的地方,实际上在整个Laravel的框架代码里也没有发现蛛丝马迹,那么这些环境变量是如何保存进来的呢?

如果Laravel框架里没有执行这些代码,我们应该可以推测是框架使用的第三方组件做了这些事情

而事实也确实如此,可以看到在DetectEnvironment类的bootstrap方法里实例化了一个Dotenv类的对象,而Dotenv\Loader正是执行了读取.env文件,执行putenv的操作。

vlucas/phpdotenv Laravel那一套.env文件的玩法就是使用的这个组件,有兴趣的同学可以研究一下

好了,暂时总结一下分析的结果

环境变量的读取函数env是在helpers.php里定义的,执行的是php的getenv
环境变量的存储经过确认是第三方的 vlucas/phpdotenv 来完成的
那么env获取不到值只能说明Dotenv的实例化并没有执行

再仔细看一下DetectEnvironment类,在实例化Dotenv前,先进行了一个 if 判断

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

而这个方法的作用就是判断 bootstrap/cache/config.php 缓存文件是否存在,如果文件存在则不会执行Dotenv的实例化操作,也就不会往$_ENV里存数据,自然env函数是取不到值的

bootstrap/cache/config.php是执行下面的命令生成的

# 对config目录下的所有配置文件做的缓存
php artisan config:cache

比如:开发时没有执行 config:cache 命令,而项目上线后为了优化访问速度,生成了缓存文件,导致env取值失败,可能就会就不一致
如果env不能使用,那该使用什么方式呢?
本着一探究竟的态度,仔细阅读了文档,在 Upgrade Guide 里找到了答案

如果使用了config:cache,env函数只能在config目录下的配置文件的php里使用,不可以在其他地方使用。

一个非常简单的办法就是将

env('APP_ENV')

改为

config('app.env')

config函数会优先读取 bootstrap/cache/config.php 中缓存的配置,如果没有缓存文件,则会直接读取 config 目录下的所有配置文件

想研究这块代码实现的可以看下另一个bootstrapper: LoadConfiguration,它是用来初始化 config
service 的,而 config 函数使用的就是这个 service

相关文章:
Laravel ENV—— 环境变量的加载与源码解析

参考
Laravel中env函数的小坑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值