![ThinkPHP实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/852/26943852/b_26943852.jpg)
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所示结果,证明设置成功。
![](https://epubservercos.yuewen.com/DB83A9/15367251204210306/epubprivate/OEBPS/Images/Figure-0034-0010.jpg?sign=1738872470-JzGgm7JQ54sa1fC9pDhrl9gfGvsPUvMs-0-250cb2b560cda29fb7a6785130d3f3f6)
图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所示页面。
![](https://epubservercos.yuewen.com/DB83A9/15367251204210306/epubprivate/OEBPS/Images/Figure-0035-0011.jpg?sign=1738872470-nVNjuhSxunaNRiHAFBsdJKbNEI4o9NTD-0-7e06e44d709a766463d857ee8f10f369)
图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所示界面。
![](https://epubservercos.yuewen.com/DB83A9/15367251204210306/epubprivate/OEBPS/Images/Figure-0037-0012.jpg?sign=1738872470-HUcFYpb70jFEOZvgyzOXi7wW6B10wxPh-0-83ca0ba97073277361c914f5316c04a1)
图2-3
二级配置的写入操作和读取类似,这里笔者就不赘述了。