IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> laravel中env底层加载和解析原理 -> 正文阅读

[PHP知识库]laravel中env底层加载和解析原理

前言

我们的应用程序几乎都会遇到不同环境需要不同的配置文件,比如最常见的开发环境需要连接开发数据库,生产需要连接生产库。记的自己曾经有个项目的做法是写两个配置文件,然后定义一个常量IS_PRODUCTION,默认是false,然后根据这个常量取配置文件,因为当时不是自动化部署,最闹心的就是每次上线之后还要去线上服务器手动将这个常量的值改为true。终于使用了laravel和自动化部署开发,完美的解决了不同环境加载不同配置文件,再也不用担心环境多配置文件乱的问题了。今天我们先来看看laravel中env的加载。

env的使用

一般程序至少都会有开发、测试、生产三个环境。我一般习惯有.env、.env.test、.env.prod三个文件。然后在测试和环境的nginx配置中将fastcgi_param APP_ENV分别设置为testing和prod,这样就可以实现开发环境加载.env测试环境加载.env.test生产环境加载.env.prod了,下边给出nginx中的一部分配置。

location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass   php:9000;
        fastcgi_index  index.php;
        include        fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param APP_ENV test;
    }

获取不同的env文件的原理

laravel中在处理请求之前是要先注册和引导程序的,加载env配置就是发生在引导阶段,其实我们的环境配置是最先被引导进来的。

class LoadEnvironmentVariables
{
   public function bootstrap(Application $app)
    {
        if ($app->configurationIsCached()) { //配置文件是否已经被缓存
            return;
        }

        $this->checkForSpecificEnvironmentFile($app); //设置配置文件的路径,也就是在这里决定取哪个env文件

        try {
            (new Dotenv($app->environmentPath(), $app->environmentFile()))->load(); //加载配置文件,并设置环境变量
        } catch (InvalidPathException $e) {
            //
        } catch (InvalidFileException $e) {
            die('The environment file is invalid: '.$e->getMessage());
        }
    }

    protected function checkForSpecificEnvironmentFile($app)
    {
        if ($app->runningInConsole() && ($input = new ArgvInput)->hasParameterOption('--env')) { //如果是命令行运行的并且设置了--env参数则加载.env连接--env参数的值
            if ($this->setEnvironmentFilePath(
                $app, $app->environmentFile().'.'.$input->getParameterOption('--env')
            )) {
                return;
            }
        }

        if (! env('APP_ENV')) { //如果环境变量APP_ENV没有获取到,则使用默认的.env
            return;
        }

        $this->setEnvironmentFilePath( //否则为  '.env'连接环境变量的值
            $app, $app->environmentFile().'.'.env('APP_ENV')
        );
    }
    protected function setEnvironmentFilePath($app, $file)
    {
        if (file_exists($app->environmentPath().'/'.$file)) {
            $app->loadEnvironmentFrom($file);

            return true;
        }

        return false;
    }
}

class Application
{
  public function environmentFile()
    {
       //这里的environmentFile默认为.env
        return $this->environmentFile ?: '.env';
    }

  public function loadEnvironmentFrom($file) //设置配置文件路径
    {
        $this->environmentFile = $file;

        return $this;
    }
}

这里的checkForSpecificEnvironmentFile就决定了程序会加载哪个配置文件,对于命令行执行的会用 $app->environmentFile连接上参数--env的值,如果获取不到APP_ENV的环境变量就取$app->environmentFile,否则用$app->environmentFile连接上环境变量APP_ENV的值。其中如果$appenvironmentFile这个值没有特殊设置他的默认值就是".env"。

env加载的内容

有了env的路径之后,这个文件里的各种配置信息是如何用到程序中的呢?

class Dotenv //
{
    public function __construct($path, $file = '.env')
    {
        $this->filePath = $this->getFilePath($path, $file);
        $this->loader = new Loader($this->filePath, true);
    }
    
  public function load()
    {
        return $this->loader->setImmutable(true
)->load();
    }

   
}

class Loader
{
  public function load()
    {
        $this->ensureFileIsReadable(); //确保文件的可读性

        $filePath = $this->filePath;
        $lines = $this->readLinesFromFile($filePath); //读取配置文件并存入数组
        foreach ($lines as $line) {
            if (!$this->isComment($line) && $this->looksLikeSetter($line)) { //排除注释将其它的设置项配置为环境变量
                $this->setEnvironmentVariable($line);
            }
        }

        return $lines;
    }

  public function setEnvironmentVariable($name, $value = null)
    {
        list($name, $value) = $this->normaliseEnvironmentVariable($name, $value); //将读取的文件修改为键值型的

        $this->variableNames[] = $name;

        if ($this->immutable && $this->getEnvironmentVariable($name) !== null) { //这里是一个点,如果外部已经设置了环境变量则使用外部的,
            return;
        }

      //如果外部没有设置则将配置文件中的设为环境变量
        if (function_exists('apache_getenv') && function_exists('apache_setenv') && apache_getenv($name) !== false) {
            apache_setenv($name, $value);
        }

        if (function_exists('putenv')) {
            putenv("$name=$value");
        }

        $_ENV[$name] = $value;
        $_SERVER[$name] = $value;
    }
}

在env的加载中Loader完成了文件的实际加载和处理,他先将配置文件读取到数组中,把非注释部分的键值设置为环境变量,这里有个细节就是在设置为环境变量之前会先判断环境变量是否存在,只会将存在与配置文件中但不在环境变量的值,设为环境变量,这句话有点绕总之意思就是系统的环境变量的优先级要高于配置文件中的配置,配置文件中的配置不会重写环境变量里的值。

env的读取

function env($key, $default = null)
    {
        $value = getenv($key); 

        if ($value === false) {
            return value($default);
        }

        switch (strtolower($value)) {
            case 'true':
            case '(true)':
                return true;
            case 'false':
            case '(false)':
                return false;
            case 'empty':
            case '(empty)':
                return '';
            case 'null':
            case '(null)':
                return;
        }

        if (($valueLength = strlen($value)) > 1 && $value[0] === '"' && $value[$valueLength - 1] === '"') {
            return substr($value, 1, -1);
        }

        return $value;
    }

这里的核心就是getenv()就是获取一个环境变量的值,其实整个env的核心就是将配置存入环境变量然后再从环境变量中取出提供给应用程序。

最后

这个就是我们根据不同环境加载不同配置文件的过程,最后在说一下其实在实际工作中各个环境的nginx配置也应该用同一份,我在实际的开发中用的是docker部署的所以将nginx中fastcgi_param APP_ENV test的test用了一个变量ENVIRONMENT_TYPE代替了,在docker容器生成时传进去一个环境变量然后使用sed命令将ENVIRONMENT_TYPE用环境变量替换掉。


?

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章           查看所有文章
加:2021-09-04 17:17:00  更:2021-09-04 17:19:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 10:16:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码