thinkphp5.1 config类和env类源码剖析

  此章节带领读者来一起阅读config类和env类,这两个类是tp5.1加载配置的核心类,看懂了这两个类以后,再结合app类初始化部分,tp5.1的配置加载规则将一目了然。

  此博客专门介绍这两个类,后续有专门的博客专门介绍tp5.1配置的加载,不过为了更好理解代码,这里也会插入。

  config类代码刨析:

(一)主要成员属性以及构造方法

   

config类是由app容器类加载的,app继承了container类,因此读过容器部分的代码就知道,当config实例化的时候,调用__make函数,将app类中赋值的属性$this->configPath以及$this->configExt注入进config,作为config类初始化的值。相关代码:

先解释下这个函数是干什么的:这段函数就是入口文件执行的run方法的最开头部分:

然后,app类先初始化自己,这样$this->configPath以及$this->configExt就初始化好了,当调用不存在的成员变量:$this->config时就会去实例化config类,并将$this->configPath以及$this->configExt两个属性注入config,初始化config.

初始化完成后,config类最核心的函数以及它的作用如图:

ArrayAccess我在容器的文章讲解了,这里不过多阐述。主要核心函数由图可知。

我们先看set方法:

    /**
     * 设置配置参数 name为数组则为批量设置
     * @access public
     * @param  string|array  $name 配置参数名(支持三级配置 .号分割)  如 配置文件名.键值.下级键值一共三级,支持到二维数组
     * @param  mixed         $value 配置值
     * @return mixed
     */
    public function set($name, $value = null)
    {
        if (is_string($name)) {
            if (false === strpos($name, '.')) {
                $name = $this->prefix . '.' . $name;
            }

            $name = explode('.', $name, 3);   //e.g.   app.debug

            if (count($name) == 2) {    //e.g.  $this->config['app']['debug'] = xxx
                $this->config[strtolower($name[0])][$name[1]] = $value;
            } else {       //e.g.   $this->config['app']['debug']['xxxx'] = xxx
                $this->config[strtolower($name[0])][$name[1]][$name[2]] = $value;
            }

            return $value;
        } elseif (is_array($name)) {
            // 批量设置
            if (!empty($value)) {
                if (isset($this->config[$value])) {
                    $result = array_merge($this->config[$value], $name);      //将同属于app配置文件的配置归类于$this->config['app']下,其他文件的配置也是如此分类
                } else {
                    $result = $name;
                }

                $this->config[$value] = $result;                                 //将同属于app配置文件的配置归类于$this->config['app']下,其他文件的配置也是如此分类
            } else {
                $result = $this->config = array_merge($this->config, $name);      //$this->config->set(include $this->thinkPath . 'convention.php');没有传value,直接将配置文件返回的数组合并
            }
        } else {
            // 为空直接返回 已有配置
            $result = $this->config;
        }

        return $result;
    }

 

set方法简要分为4个场景:

1.初始化惯例配置的时候使用的set方法。这个场景在APP类initialize()方法中,代码如下:

走到此处:

 

2.读取配置文件,配置文件所返回的数组走到第二大分支的逻辑  is_array($name) ,该场景和第一点一样,是同样的逻辑分支,但它执行的地方是此处:

 

3.当$name是字符时,则直接设置。如果不是以xx.xx的形式传入,只有一个name值,则默认加上app前缀,意思是默认给app配置文件添加配置。对应代码:

.e.g    当传入的参数是$name = 'app.name' 和 $value = 'xxxx' 时,则设置,$this->config['app']['debug'] =  xxxx;  $name = explode('.', $name, 3);  语句可知,

最多只能支持设置三维数组。比如:$this->config['app']['debug']['xxx'] =  xxxx; 

 

PS:$this->config['app']['debug']['xxx']数组中存在这样的对应关系,第一维的键对应相应的配置文件,比如  $this->config['app']对应app.php的配置文件。

接下来后面的二维或者到三维数组的元素是该文件下的配置。比如:$this->config['app']['debug']['xxx']  中的['debug']['xxx']是app.php配置文件的某项配置。

所有配置会按照这种形式,以第一维的键对应配置的文件名,归类并对应到各自的文件名键中去,保存在$this->config中。

 

4.最后一个逻辑分支:$name为空时,返回$this->config.

 

总结:在APP类执行初始化加载配置时,主要用到了第一和第二个场景

 

看完set方法,再看到get方法的场景:

代码:

1.没有指定配置文件。

.e.g  比如:app.debug ,你不写app,只写了debug,则函数默认给你加上app,意思是该配置默认为app.xxx

 

2.无参数时,将获取所有保存在属性config中的配置

 

3.获取某配置文件下所有的配置

.e.g    当输入$name为'app.'  ,如果你的获取是这样写的就会执行这一段代码,substr($name, 0, -1)=>将最后的.去掉,比如app. 就变成 app.此时执行pull函数

     /**
     * 获取一级配置
     * @access public
     * @param  string    $name 一级配置名
     * @return array
     */
    public function pull($name)
    {
        $name = strtolower($name);

        if ($this->yaconf) {   //如果yaconf开启
            $yaconfName = $this->getYaconfName($name);

            if (Yaconf::has($yaconfName)) {
                $config = Yaconf::get($yaconfName);
                return isset($this->config[$name]) ? array_merge($this->config[$name], $config) : $config;  //假设name是app,如果yaconf的app有数据,就会把$this->config['app']的东西和yaconf合并返回(相同键的元素,yaconf会覆盖,优先级高)
            }
        }

        return isset($this->config[$name]) ? $this->config[$name] : [];    //假设name是app,直接返回$this->config['app']的内容
    }

ps:如果开启了yaconf,则会将yaconf的内容和当前的的配置合并,相同元素以yaconf为准.   否则,返回config属性所保存的配置

 

4.正常获取配置

.e.g   传入app.debug,就返回app配置文件下debug的配置

 

get和set方法均已讲解完毕,目光看到load方法:

这段代码关联到app类的init()方法:

根据app执行时,config类去加载app类决定执行的对应后缀的配置文件。因此,这里便使用到工厂模式,以用来加载和app类执行的相应后缀的配置文件。

    protected function loadFile($file, $name)
    {
        $name = strtolower($name);
        $type = pathinfo($file, PATHINFO_EXTENSION);   //$type是返回配置文件后缀信息

        if ('php' == $type) {
            return $this->set(include $file, $name);
        } elseif ('yaml' == $type && function_exists('yaml_parse_file')) {
            return $this->set(yaml_parse_file($file), $name);
        }

        return $this->parse($file, $type, $name);
    }


     /**
     * 解析配置文件或内容
     * @access public
     * @param  string    $config 配置文件路径或内容 ,例如这样的 E:\phpstudy_pro\WWW\tp5.1\config\database.php
     * @param  string    $type 配置解析类型
     * @param  string    $name 配置名(如设置即表示二级配置)
     * @return mixed
     */
    public function parse($config, $type = '', $name = '')
    {
        if (empty($type)) {
            $type = pathinfo($config, PATHINFO_EXTENSION);
        }
        //工厂模式
        $object = Loader::factory($type, '\\think\\config\\driver\\', $config);

        return $this->set($object->parse(), $name);
    }




工厂的代码内容,可以阅读容器的章节,属于容器创建对象的内容。

总结:config类核心功能可以看前面的图即可。

 

ENV类刨析

env类核心有这几个类:

     /**
     * 读取环境变量定义文件
     * @access public
     * @param  string    $file  环境变量定义文件
     * @return void
     */
    public function load($file)
    {
        $env = parse_ini_file($file, true);
        $this->set($env);
    }

    /**
     * 获取环境变量值
     * @access public
     * @param  string    $name 环境变量名
     * @param  mixed     $default  默认值
     * @return mixed
     */
    public function get($name = null, $default = null, $php_prefix = true)
    {
        //没有指定配置时,全部返回
        if (is_null($name)) {
            return $this->data;
        }

        $name = strtoupper(str_replace('.', '_', $name));

        if (isset($this->data[$name])) {   //var_dump($this->data);
            return $this->data[$name];
        }
//        echo $name;echo "\n";
//        var_dump($this->getEnv($name, $default, $php_prefix));
        //若data数组没有,则去系统变量中看看有无数据
        return $this->getEnv($name, $default, $php_prefix);
    }

    //获取系统的环境变量,分php的系统变量或者其他变量
    protected function getEnv($name, $default = null, $php_prefix = true)
    {
        if ($php_prefix) {
            $name = 'PHP_' . $name;
        }

        //内置函数,获取系统环境变量
        $result = getenv($name); // var_dump($result);

        //返回默认的配置
        if (false === $result) {
            return $default;
        }

        if ('false' === $result) {
            $result = false;
        } elseif ('true' === $result) {
            $result = true;
        }

        //系统变量,如果data没保存,则注册到data
        if (!isset($this->data[$name])) {
            $this->data[$name] = $result;
        }

        return $result;
    }

    /**
     * 设置环境变量值
     * @access public
     * @param  string|array  $env   环境变量
     * @param  mixed         $value  值
     * @return void
     */
    public function set($env, $value = null)  //先分析功能,再分析使用场景
    {
        if (is_array($env)) {
            $env = array_change_key_case($env, CASE_UPPER);            //将所有配置数组的键转为大写
                                                                      //this->data 的键值对,THINK_PATH => E:\phpstudy_pro\WWW\tp5.1\thinkphp\  它的格式统一的  so on
            foreach ($env as $key => $val) {
                if (is_array($val)) {
                    foreach ($val as $k => $v) {
                        $this->data[$key . '_' . strtoupper($k)] = $v;       //例如:[APP=>['path'=>'xxxx']],形成格式一样是,两个大写的单词用下划线拼接。它的格式是统一的,同上的键值对形式 THINK_PATH => E:\phpstudy_pro\WWW\tp5.1\thinkphp\
                    }
                } else {
                    $this->data[$key] = $val;    //将env的东西保存到data,THINK_PATH => E:\phpstudy_pro\WWW\tp5.1\thinkphp\
                }
            }
        } else {
            $name = strtoupper(str_replace('.', '_', $env));  //将.改为下划线,然后全部转大写

            $this->data[$name] = $value;
        }
    }

它在app类中关于关联config的执行部分:

流程:

查看load,set两个函数代码可知,.env的配置内容 : CONFIG_EXT= .PHP(或者其他后缀,一旦指定后缀,只能加载指定后缀的配置文件)

调试代码的方法:

1.不停的打断点调试

2.在调用的函数使用php内置函数debug_backtrace查看改函数的调用情况

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: thinkphp5.1是一款基于PHP语言的MVC框架,它采用了Laravel框架中的一些优秀设计思想,并在此基础上进行了改进和优化,是一款颇受欢迎的PHP框架。 该框架具有非常完善的文档和教程,学习起来非常容易。它的核心思想是“约定优于配置”,通过一些默认的规则来简化代码,提高开发效率。同时,它也提供了很多实用的工具和函数,如请求对象、响应对象、验证器、缓存处理、日志记录等,使得开发者能够更加便捷地实现业务逻辑。 在源码方面,thinkphp5.1采用了比较优秀的代码结构和注释规范,代码风格清晰易读,符合现代编程的标准。同时,它也支持非常灵活的扩展机制,可以通过composer方式引入其他第三方组件来扩展功能。 总的来说,thinkphp5.1源码是一款非常优秀的PHP框架,具有清晰的代码结构、丰富的功能和非常好的可扩展性,适合开发各种规模的Web应用程序。 ### 回答2: ThinkPHP 5.1是一个基于MVC设计模式的PHP开源框架,它的源码是开放的,可以供开发者进行学习和使用。通过阅读ThinkPHP 5.1源码,开发者可以深入了解框架的核心设计思想和运行原理,从而更好地进行二次开发和定制。ThinkPHP 5.1源码的主要特点包括:使用面向对象的编程思想,提供了丰富的内置库函数和库,支持依赖注入和控制反转,提供了强大的缓存机制,支持多种数据库操作,具有良好的安全性和可扩展性。此外,ThinkPHP 5.1还提供了详细的文档和示例代码,方便开发者学习和使用。总之,ThinkPHP 5.1源码为PHP开发者提供了强有力的支持,帮助开发者快速高效地开发出安全、稳定、高性能的web应用程序。 ### 回答3: thinkphp5.1源码是一个基于PHP的开发框架,它的思想是快速、可靠、简单、灵活,它提供了许多丰富的功能,包括模板引擎、数据库访问、缓存机制等等。 thinkphp5.1源码是一个开放源代码的框架,目前为止已经发展成为非常成熟的架构体系,拥有非常多的使用者和开发者,也得到了非常多的好评和支持。 thinkphp5.1源码的特点是快速开发、规范化开发、灵活、可扩展,它采用MVC的设计模式,在架构上很好地实现了分层开发原则,从而提高了开发效率和代码的可维护性。 此外,thinkphp5.1源码在数据库访问、缓存机制、模板引擎等方面也都有很好的支持,通过它们能够更好地管理数据、提高应用的性能和减少开发周期。 总之,thinkphp5.1源码具有很好的可用性和可扩展性,它已经成为PHP开发者中的主流框架之一,许多项目都已经采用了它的开发方式,包括PHP电商、PHP CMS等等,而且它也在不断不断地完善,使得它在未来的开发过程中仍然能保持其领先地位。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值