当前位置: 首页 > article >正文

laravel .env环境变量原理

介绍

对于应用程序运行的环境来说,不同的环境有不同的配置通常是很有用的。Laravel 利用 Vance Lucas 的 PHP 库 DotEnv 使得此项功能的实现变得非常简单。当应用程序收到请求时,.env 文件中列出的所有变量将被加载到 PHP 的超级全局变量 $_ENV 中。

使用

你可以使用 env 函数检索这些变量的值。事实上,如果你查看 Laravel 的配置文件,你就能注意到有数个选项已经使用了这个函数:

'debug' => env('APP_DEBUG', false),

传递给 env 函数的第二个值是「默认值」。如果给定的键不存在环境变量,则会使用该值。

使用分析

我们可以先看一下助手函数 env

if (! function_exists('env')) {
    /**
     * Gets the value of an environment variable.
     *
     * @param  string  $key
     * @param  mixed  $default
     * @return mixed
     */
    function env($key, $default = null)
    {
        return Env::get($key, $default);
    }
}

ENV::get 最终追踪到 EnvConstAdapter get

    /**
     * Get an environment variable, if it exists.
     *
     * @param string $name
     *
     * @return \PhpOption\Option
     */
    public function get($name)
    {
        if (array_key_exists($name, $_ENV)) {
            return Some::create($_ENV[$name]);
        }

        return None::create();
    }

读取$_ENV内容,$_ENV是 通过环境提供给脚本的变量

/**
 * @xglobal $_ENV array
 *
 * Variables provided to the script via the environment.
 * Analogous to the old $HTTP_ENV_VARS array (which is still available, but deprecated).
 *
 * <p><a href="https://secure.php.net/manual/en/reserved.variables.php">
 * https://secure.php.net/manual/en/reserved.variables.php</a>
 */
$_ENV = array();

写入$_ENV

bootstrap/app.php中

    try {
        (new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(dirname(__DIR__)))->bootstrap();
    } catch (Dotenv\Exception\InvalidPathException $e) {
        //
    }

Laravel\Lumen\Bootstrap\LoadEnvironmentVariables 中

<?php

namespace Laravel\Lumen\Bootstrap;

use Dotenv\Dotenv;
use Dotenv\Exception\InvalidFileException;
use Illuminate\Support\Env;
use Symfony\Component\Console\Output\ConsoleOutput;

class LoadEnvironmentVariables
{
    /**
     * The directory containing the environment file.
     *
     * @var string
     */
    protected $filePath;

    /**
     * The name of the environment file.
     *
     * @var string|null
     */
    protected $fileName;

    /**
     * Create a new loads environment variables instance.
     *
     * @param  string  $path
     * @param  string|null  $name
     * @return void
     */
    public function __construct($path, $name = null)
    {
        $this->filePath = $path;
        $this->fileName = $name;
    }

    /**
     * Setup the environment variables.
     *
     * If no environment file exists, we continue silently.
     *
     * @return void
     */
    public function bootstrap()
    {
        try {
            $this->createDotenv()->safeLoad();
        } catch (InvalidFileException $e) {
            $this->writeErrorAndDie([
                'The environment file is invalid!',
                $e->getMessage(),
            ]);
        }
    }

    /**
     * Create a Dotenv instance.
     *
     * @return \Dotenv\Dotenv
     */
    protected function createDotenv()
    {
        return Dotenv::create(
            $this->filePath,
            $this->fileName,
            Env::getFactory()
        );
    }

    /**
     * Write the error information to the screen and exit.
     *
     * @param  string[]  $errors
     * @return void
     */
    protected function writeErrorAndDie(array $errors)
    {
        $output = (new ConsoleOutput)->getErrorOutput();

        foreach ($errors as $error) {
            $output->writeln($error);
        }

        die(1);
    }
}

我们可以看到 bootstrap方法是创建Dotenv实例,并且调用Dotenv实例的safeload方法,Dotenv::create参数的含义

   $this->filePath, #env所在目录
   $this->fileName, #env名称,默认 .env
   Env::getFactory() #laravel env相关的适配器工厂

由此我们可以自定义.env的位置和名称

safeload方法

    /**
     * Load environment file in given directory.
     *
     * @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
     *
     * @return array<string|null>
     */
    public function load()
    {
        return $this->loadData();
    }

    /**
     * Load environment file in given directory, silently failing if it doesn't exist.
     *
     * @throws \Dotenv\Exception\InvalidFileException
     *
     * @return array<string|null>
     */
    public function safeLoad()
    {
        try {
            return $this->loadData();
        } catch (InvalidPathException $e) {
            // suppressing exception
            return [];
        }
    }

    /**
     * Load environment file in given directory.
     *
     * @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
     *
     * @return array<string|null>
     */
    public function overload()
    {
        return $this->loadData(true);
    }

    /**
     * Actually load the data.
     *
     * @param bool $overload
     *
     * @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidFileException
     *
     * @return array<string|null>
     */
    protected function loadData($overload = false)
    {
        return $this->loader->setImmutable(!$overload)->load();
    }

根据代码分析,safeLoad 中使用了 try {} catuch {} 捕获了异常,不会因为地址错误而报错,同时加载loadData,这里默认使用了loadData = true, 影响的Dotenv 创建的 DotenvVariables(array $adapters, $immutable)实例属性 $immutable值。我们通过追踪load方法,最终可以找到该方法:

    /**
     * Set an environment variable.
     *
     * @param string      $name
     * @param string|null $value
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function set($name, $value = null)
    {
        if (!is_string($name)) {
            throw new InvalidArgumentException('Expected name to be a string.');
        }

        // Don't overwrite existing environment variables if we're immutable
        // Ruby's dotenv does this with `ENV[key] ||= value`.
        if ($this->isImmutable() && $this->get($name) !== null && $this->loaded->get($name)->isEmpty()) {
            return;
        }

        $this->setInternal($name, $value);
        $this->loaded->set($name, '');
    }

此时我们明白,如果$immutable = true的话,如果之前环境变量有了该值,后面的配置文件无法进行更改环境变量的值,如果没有该值进行添加


http://www.kler.cn/news/355514.html

相关文章:

  • 用Python删除PDF文档页面的页边距
  • ts 中 Omit 作用
  • JavaScript 第17章:性能优化
  • Chapter09
  • perl替换文件中的特定内容
  • 海南聚广众达电子商务咨询有限公司靠谱吗怎么样?
  • Uptime Kuma: 全面的开源网站监控解决方案
  • 青少年编程能力等级测评CPA C++(二级)试卷(2)
  • JavaScript的第三天
  • VSCode C/C++跳转到定义、自动补全、悬停提示突然失效
  • Rocky Linux 9安装Asterisk 20和freepbx 17脚本——筑梦之路
  • Rust各个方面完胜C++吗?
  • Threejs 实现3D 地图(01)创建基本场景
  • Parameter-Efficient Fine-Tuning for Large Models: A Comprehensive Survey阅读笔记
  • LeetCode1658.将x减到0的最小操作数
  • PHP爬虫API:获取商品详情的新利器
  • uniapp uni.uploadFile errMsg: “uploadFile:fail
  • PTA L1系列题解(C语言)(L1_073 -- L1_080)
  • php常用设计模式之单例模式
  • HikariPool连接池报错(Possibly consider using a shorter maxLifetime value)