Laravel在启动过程中会加载其环境变量,这是众所周知的。但具体如何操作以及在哪里进行呢?答案就在Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables类中。实际上,这个过程非常简单。正如我们将在下面的详细解释中所看到的,Laravel遵循了几个步骤。让我们一步一步地了解这些步骤。

class LoadEnvironmentVariables
{
    /**
     * 启动给定的应用程序
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        if ($app->configurationIsCached()) {
            return;
        }

        $this->checkForSpecificEnvironmentFile($app);

        try {
            $this->createDotenv($app)->safeLoad();
        } catch (InvalidFileException $e) {
            $this->writeErrorAndDie($e);
        }
    }
}

步骤解析

1、检查配置缓存

首先,bootstrap 方法会检查应用程序配置是否被缓存。如果已缓存,则直接返回,不再加载环境变量。

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

2、检查环境配置文件

然后,该方法会检查是否存在特定环境配置文件。例如,如果当前环境为 production,则会检查是否存在 .env.production 文件。

$this->checkForSpecificEnvironmentFile($app);

3、创建并加载 .env 文件

如果不存在特定环境配置文件,则会创建 .env 文件并加载其中的环境变量。

try {
    $this->createDotenv($app)->safeLoad();
} catch (InvalidFileException $e) {
    $this->writeErrorAndDie($e);
}

配置缓存

1、检查配置缓存文件是否存在

configurationIsCached 方法检查是否存在 ./config.php 文件,该文件位于缓存目录中。如果文件存在,则意味着配置已缓存。

public function configurationIsCached()
{
    return is_file($this->getCachedConfigPath());
}

2、获取配置缓存文件的路径

getCachedConfigPath 方法返回配置缓存文件的路径。

public function getCachedConfigPath()
{
    return $this->normalizeCachePath('APP_CONFIG_CACHE''cache/config.php');
}

配置未缓存

如果配置未缓存,则 Laravel 会执行以下操作:

1、检查是否指定了环境文件

如果应用程序在控制台中运行并且指定了 --env 参数,则 Laravel 会将环境文件设置为命令中指定的内容。

protected function checkForSpecificEnvironmentFile(Application $app)
{
    if ($app->runningInConsole() &&
        ($input = new ArgvInput)->hasParameterOption('--env') &&
        $this->setEnvironmentFilePath($app$app->environmentFile() . '.' . $input->getParameterOption('--env'))) {
        return;
    }

    // ...
}

2、获取环境变量

Laravel 会从 .env 文件中获取 APP_ENV 环境变量。

$environment = Env::get('APP_ENV');

3、设置环境文件

如果 APP_ENV 环境变量存在,则 Laravel 会将环境文件设置为 APP_ENV 的值。

if ($environment) {
    $this->setEnvironmentFilePath($app$app->environmentFile() . '.' . $environment);
}

读取 .env 文件解析

1、确定环境文件

在加载环境变量之前,Laravel 会先确定环境文件。它会检查以下情况:

  • 外部环境变量: 是否从外部环境变量中提供了 APP_ENV 变量。
  • CLI 参数: 是否指定了 --env CLI 参数。
    1.1 从外部环境变量中获取 APP_ENV

如果 APP_ENV 环境变量存在于外部环境中,则 Laravel 会将其作为环境文件的后缀。例如,如果 APP_ENV 的值为 production,则 Laravel 会尝试加载 .env.production 文件。

    1.2 从 CLI 参数中获取环境文件

如果指定了 --env CLI 参数,则 Laravel 会将其值作为环境文件的后缀。例如,如果使用 php artisan serve --env=staging 命令启动应用程序,则 Laravel 会尝试加载 .env.staging 文件。

    1.3 加载默认环境文件

如果上述两种情况都不满足,则 Laravel 会加载默认的环境文件 ./env

2、创建 Dotenv 实例

确定环境文件之后,Laravel 会创建一个 Dotenv 组件的实例。该实例将用于加载和解析 .env 文件中的配置。

3、解析 .env 文件

Dotenv 实例会使用 safeLoad 方法加载 .env 文件,并返回配置数组。

    3.1 安全加载 .env 文件

safeLoad 方法会尝试加载 .env 文件。如果文件不存在或无法读取,则会返回空数组。

    3.2 解析 .env 文件内容

safeLoad 方法会调用 load 方法加载 .env 文件内容,并将其传递给 parse 方法进行解析。

    3.3 解析 .env 文件格式

parse 方法会解析 .env 文件中的内容,并将其转换为键值对数组。

4、异常处理

  • InvalidPathException: 如果 .env 文件不存在或无法读取,则会抛出此异常。
  • InvalidFileException: 如果 .env 文件格式错误,则会抛出此异常。
// 确定环境文件
$envFile = $app->environmentFile();
if ($app->runningInConsole() && $input = new ArgvInput()) {
    if ($input->hasParameterOption('--env')) {
        $envFile = $app->environmentPath() . '.' . $input->getParameterOption('--env');
    }
}

// 创建 Dotenv 实例
$dotenv = Dotenv::create(
    Env::getRepository(),
    $app->environmentPath(),
    $envFile
);

// 解析 .env 文件
try {
    $dotenv->safeLoad();
} catch (InvalidFileException $e) {
    $this->writeErrorAndDie($e);
}

总结

1、缓存检查

Laravel 会检查环境变量是否已缓存,如果已缓存则直接读取。

2、环境文件确定

Laravel 会根据 --env CLI 参数或 APP_ENV 环境变量确定要加载的环境文件。

3、Dotenv 实例创建

Laravel 创建 Dotenv 实例用于加载和解析 .env 文件。

4、安全加载环境变量

Dotenv 实例使用 safeLoad 方法安全加载 .env 文件,并处理异常。

5、异常处理

处理 .env 文件不存在或格式错误等异常情况。