Laravel、Lumen中自动加载对应环境env文件配置

in LaravelPHP with 0 comment

前情提要

一般程序至少都会有开发、测试、生产三个环境。我一般习惯有.env、.env.test、.env.production 三个文件

如果每次被动的去相应的环境修改env配置的话,是一件很麻烦的事情

nginx配置

# example.conf
# 见 fastcgi_param 参数
location ~ \.php$ {
    fastcgi_pass   php72:9000;
    fastcgi_index  index.php;
    include        fastcgi_params;
    fastcgi_param  PATH_INFO $fastcgi_path_info;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_param  APP_ENV production; 
}

lumen下的使用

# bootstrap/app.php
require_once __DIR__.'/../vendor/autoload.php';

# 配置env文件
$environment = env('APP_ENV', false);
$environment_file = !env('APP_ENV', false) ? '.env' : ".env.$environment";
(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
    dirname(__DIR__), $environment_file
))->bootstrap();

laravel下的使用

laravel下使用无需进行配置, 具体原因见如下分析

原理分析

其实 lumen 和 laravel 加载 env 的配置都差不多,主要可见 Dotenv\Dotenv 类, 从而读取配置信息

lumen中依赖的启动方式在主要在app.php

(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
    dirname(__DIR__)
))->bootstrap();

我们可以看到 加载 env file 和 env path,是直接进行初始化的

public function __construct($path, $name = null)
{
    $this->filePath = $path;
    $this->fileName = $name;
}

我们再来看下laravel的

# 启动器
$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

# 这里实现一个单例: 重要之处
$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);

完成后返回一个app, 在public/index.php

它会先从容器中解析出类实例

Illuminate\Contracts\Http\Kernel::class
对应
App\Http\Kernel::class

解析后

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

# 执行handle方法
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

handle方法是怎么来的呢,见App\Http\Kernel::class

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel{
    ...
}

我们发现在 Kernel 没有handle这个方法,所以这里执行的handle是父方法的handle : Illuminate\Foundation\Http\Kernel

# step1
$response = $this->sendRequestThroughRouter($request);

# step2
$this->bootstrap();

# step3
$this->app->bootstrapWith($this->bootstrappers());

# 注:
$this->bootstrappers = [
    'Illuminate\Foundation\Bootstrap\DetectEnvironment',
    'Illuminate\Foundation\Bootstrap\LoadConfiguration',
    'Illuminate\Foundation\Bootstrap\ConfigureLogging',
    'Illuminate\Foundation\Bootstrap\HandleExceptions',
    'Illuminate\Foundation\Bootstrap\RegisterFacades',
    'Illuminate\Foundation\Bootstrap\RegisterProviders',
    'Illuminate\Foundation\Bootstrap\BootProviders'
];

所以得到了我们的DetectEnvironment

从而具体的解析方法见

protected function checkForSpecificEnvironmentFile($app)
{
    if (! env('APP_ENV')) {
        return;
    }

    # $app->environmentFile() : .env
    # env('APP_ENV') = 'production'
    $file = $app->environmentFile().'.'.env('APP_ENV');

    if (file_exists($app->environmentPath().'/'.$file)) {
        $app->loadEnvironmentFrom($file);
    }
}

但我们在nginx中配置了 app_env的值的时候,它会自动进行拼接得到这个env file, 最后的结果为 .env.production

命令行下的使用

# 执行artisan命令
APP_ENV=production && php artisan test

参考文章:

laravel中env文件的加载: https://www.jianshu.com/p/0370072a6023

Laravel源码入门-启动引导过程:https://my.oschina.net/zhmsong/blog/900617

通过nginx的fastcgi_param来设置环境变量:https://www.cnblogs.com/gantoday/p/7465097.html

Laravel 启动流程分析 (代码全流程):
https://learnku.com/articles/19878

make使用文档: https://learnku.com/docs/laravel/7.x/container/7454#the-make-method

Comments are closed.