ThinkPHP实战
上QQ阅读APP看书,第一时间看更新

2.2 配置操作

针对配置的操作无非读写而已,ThinkPHP提供了很方便的配置操作函数C(大写字母C)。ThinkPHP按照2.1节的顺序加载完配置之后,配置全局有效,在框架作用范围内(一般指应用目录下),所有配置都可以直接使用C函数读取(包括ThinkPHP默认配置)。

在UPUPW的htdocs目录中新建一个Web项目(笔者的Web项目名称为thinkphp-inaction),目录结构如下:

      ├─chapter-2
      ├─index.php
      ├─ThinkPHP

ThinkPHP框架放在入口文件上一级主要是为了多个项目共用一套框架,节约了磁盘空间。

入口文件定义如下(以后如果没有特殊说明,项目入口文件统一为该文件):

        <? php
        /**
         *  index.php
         */
        // 检测PHP环境
        if (version_compare(PHP_VERSION, '5.3.0', '<')) die('require PHP >5.3.0 ! ');
        // 开启调试模式 建议开发阶段开启 部署阶段注释或者设为false
        define('APP_DEBUG', true);
        // 定义应用目录
        define('APP_PATH', './Application/');
        //关闭目录保护
        define('BUILD_DIR_SECURE', false);
        // 引入ThinkPHP入口文件
        require '../ThinkPHP/ThinkPHP.php';

打开浏览器,在地址栏输入localhost/chapter-2进行测试。看到“欢迎使用ThinkPHP! ”字样证明应用初始化成功。

2.2.1 C函数

作为配置操作的一个重要函数,不得不单独提下C函数。打开文件ThinkPHP/Common/functions.php,可以看到C函数定义如下:

        /**
         * 获取和设置配置参数 支持批量定义
         * @param string|array $name配置变量
         * @param mixed $value配置值
         * @param mixed $default默认值
         * @return mixed
         */
        function C($name=null, $value=null, $default=null) {
            static $_config = array();
            // 无参数时获取所有
            if (empty($name)) {
              return $_config;
            }
            // 优先执行设置获取或赋值
            if (is_string($name)) {
              if (! strpos($name, '.')) {
                  $name = strtoupper($name);
                  if (is_null($value))
                      return isset($_config[$name]) ? $_config[$name] :
    $default;
                  $_config[$name] = $value;
                  return null;
              }
              // 二维数组设置和获取支持
              $name = explode('.', $name);
              $name[0]   =  strtoupper($name[0]);
              if (is_null($value))
                  return isset($_config[$name[0]][$name[1]]) ?
    $_config[$name[0]][$name[1]] : $default;
              $_config[$name[0]][$name[1]] = $value;
              return null;
              }
              // 批量设置
              if (is_array($name)){
                  $_config = array_merge($_config,
        array_change_key_case($name, CASE_UPPER));
                return null;
              }
              return null; // 避免非法参数
          }

可以看到ThinkPHP的注释是很详尽的,就算是没有使用过C函数的程序员,看完注释之后对C函数的使用方法应该是没有问题的。C语言函数算法说明如下:

(1)定义static $_config变量,static方式定义的变量本次请求内全局有效。

(2)如果传入的$name为空,返回所有配置;如果不为空,进入第3步。

(3)判断$name是否为字符串,如果是,进入第4步;否则进入第12步。

(4)判断$name中是否有“.”,如果没有,进入第5步;否则进入第8步。

(5)将$name转换为大写,如果$value为null,进入第6步;否则进入第7步。

(6)判断是否存在名为$name的配置,如果存在,则返回该配置的值;否则返回默认值。

(7)将名称为$name的配置值设为$value,并返回null。

(8)将$name分割为数组,加入传入的$name为“user.name”,分割完之后$name为[‘user', 'name']。

(9)将$name数组的第1个元素“user”转换为大写,如果传入的$value为null,则进入第10步,否则进入第11步。

(10)判断是否存在$_config[$name[0]][$name[1]](本例中为$_config[‘user'][‘name'])的配置,如果存在,返回$_config[$name[0]][$name[1]]的值,否则返回null。

(11)将名称为$_config[$name[0]][$name[1]](本例中为$_config[‘user'][‘name'])的配置值设为$value,并返回null。

(12)如果$name是数组,则将该数组的全部键名转换为大写后合并到全局配置中去。

(13)最后返回null是为了防止非法调用函数。

通过源码分析发现,ThinkPHP的配置名称只有一级是不区分大小写的,也就是说C(‘DATA_CACHE_TYPE')和C(‘data_cache_type')的返回值是相等的,但是二级配置是区分大小写的,也就是说C(‘user.name')和C(‘user.NAME')是不相等的,这点请读者注意。另外,关于无限级配置,因为源码中可以看到ThinkPHP在对配置的处理只处理到二级,不支持二级以上配置。

2.2.2 读取配置

打开Application/Home/Controller/IndexController.class.php,更改index方法中代码如下:

        <? php
        namespace Home\Controller;
        use Think\Controller;
        class IndexController extends Controller
        {
            public function index()
            {
              echo C('DATA_CACHE_TYPE');
            }
        }

刷新浏览器,可以看到浏览器输出了“File”,证明读取配置成功,我们并没有配置DATA_CACHE_TYPE,通过2.1节的加载顺序可以发现默认配置中有DATA_CACHE_TYPE的配置。

现在开始测试公共配置的加载,打开Application/Common/Conf/config.php,设置DATA_CACHE_TYPE如下:

        <? php
        /**
         * config.php
         */
        return array(
            'DATA_CACHE_TYPE' => 'Db'
        );

刷新浏览器,可以看到浏览器输出了“Db”,公共配置已经覆盖了默认的配置“File”。

继续编辑该文件,这次添加一个二维数组,最终代码如下:

        <? php
        /**
         * config.php
         */
        return array(
            'DATA_CACHE_TYPE' => 'Db',
            'ADMIN' => array(
              'username' => 'admin',
              'password' => '123456'
            )
        );

打开Application/Home/IndexController.class.php,编辑index.php代码如下:

        <? php
        namespace Home\Controller;
        use Think\Controller;
        class IndexController extends Controller
        {
            public function index()
            {
              echo 'username: ' . C('ADMIN.username') . ', password: ' .
    C('ADMIN.password');
            }
        }

刷新浏览器,可以看到浏览器输出了“username: admin, password: 123456”,其他类型的配置读取操作与本节一致。

2.2.3 加载扩展配置

在Application/Home/Conf目录下新建admin_user.php,文件内容如下:

        <? php
        /**
         * admin_user.php
         */
        return array(
            array(
              'id' => 1,
              'username' => 'root',
              'password' => 'root'
            ),
            array(
              'id' => 2,
              'username' => 'admin',
              'password' => 'admin'
            )
        );

编辑同级的config.php,内容如下:

        <? php
        /**
        * config.php
        */
       return array(
          'LOAD_EXT_CONFIG' => array('ADMIN' => 'admin_user')
       );

编辑Application/Home/Controller/IndexController.class.php,代码如下:

        <? php
        namespace Home\Controller;
        use Think\Controller;
        class IndexController extends Controller
        {
            public function index()
            {
              print_r(C('ADMIN'));
            }
        }

刷新浏览器,如果看到如图2-1所示结果,证明设置成功。

图2-1

如果看到其他结果,请检查文件路径是否一致,如果仍不能解决问题,请前往github提问。

2.2.4 写入配置

C函数写入的配置属于“动态配置”,也就是最高优先级的配置,编辑Application/Home/Controller/IndexController.class.php,内容如下:

    class IndexController extends Controller
    {
        public function index()
        {
          echo '<pre>';
          echo "设置前:\n";
          print_r(C('ADMIN'));
          C('ADMIN', array(
              array(
                  'id' => 1,
                  'username' => 'root',
                  'password' => 'admin'
              )
          ));
          echo "设置后:\n";
          print_r(C('ADMIN'));
          echo '</pre>';
        }
    }

正式输出前后先输出“<pre>”有利于排版显示。

刷新浏览器可以看到如图2-2所示页面。

图2-2

读者可能注意到设置后的配置覆盖掉了原来的值,如果想保留原来的值应该怎么操作呢?ThinkPHP这次就没有提供相关函数给我们了,我们可以利用array_merge函数操作。

编辑Application/Home/Controller/IndexController.class.php,代码如下:

        <? php
        namespace Home\Controller;
        use Think\Controller;
        class IndexController extends Controller
        {
            public function index()
            {
              echo '<pre>';
              echo "设置前:\n";
              $admin = C('ADMIN');
              print_r($admin);
              $newAdmin = array(
                  array(
                      'id' => 1,
                      'username' => 'root',
                      'password' => 'admin'
                  )
              );
              C('ADMIN', $newAdmin);
              echo "覆盖模式设置后:\n";
              print_r(C('ADMIN'));
              $admin = array_merge($admin, $newAdmin);
              echo "合并模式设置后:\n";
              print_r($admin);
              echo '</pre>';
            }
        }

刷新浏览器,可以看到如图2-3所示界面。

图2-3

二级配置的写入操作和读取类似,这里笔者就不赘述了。