一个非常完美的读写ini格式的PHP配置类分享


Posted in PHP onFebruary 12, 2015

基本满足所有配置相关的需求。

/**
 * 解析.ini格式的配置文件为一个树形结构的对象
 * 配置文件不同section通过冒号继承
 * 默认根据hostname确定使用的section,如果不能确定就优先使用production
 * 检测环境的时候总是优先检测production,其余section按定义顺序检测
 *
 * @author ares@phpdr.net
 *    
 */
class Config {
 /**
 * 解析后的配置文件
 *
 * @var stdClass
 */
 private $config;
 /**
 * 一个二维数组,键是配置文件的section
 * 值是一个数组或回调函数
 * 如果是数组则计算hostname是否在数组中决定是否使用该section
 * 如果是回调函数通过返回值true或false来确定是否使用该section
 *
 * @var array
 */
 private $map = array ();
 
 /**
 * section会被解析,:表示继承
 * 配置项中的'.'用来区分层级关系
 * section中的'.'不会被解析,配置中的数组不受影响。
 *
 * @param string $conf     
 * @throws ErrorException
 * @return stdClass
 */
 function __construct($conf, $map) {
 $config = $this->parseIni ( ( object ) parse_ini_string ( $conf, true ) );
 if (array_key_exists ( 'production', $map )) {
  $production = $map ['production'];
  unset ( $map ['production'] );
  $map = array_merge ( array (
   'production' => $production ), $map );
 } else {
  throw new ErrorException ( 'production section not found in config' );
 }
 $section = 'production';
 $hostname = gethostname ();
 foreach ( $map as $k => $v ) {
  if (is_array ( $v )) {
  foreach ( $v as $v1 ) {
   if ($v1 == $hostname) {
   $section = $k;
   break 2;
   }
  }
  } elseif (is_callable ( $v )) {
  if (true == call_user_func ( $v )) {
   $section = $k;
   break;
  }
  } else {
  throw new ErrorException ( 'Wrong map value in ' . __CLASS__ );
  }
 }
 $this->config = $config->$section;
 }
 
 /**
 * 总是返回配置对象
 *
 * @return mixed
 */
 function __get($key) {
 if (isset ( $this->config->$key )) {
  return $this->config->$key;
 }
 }
 
 /**
 * 切分
 *
 * @param stdClass $v     
 * @param string $k1     
 * @param mixed $v1     
 */
 private function split($v, $k1, $v1) {
 $keys = explode ( '.', $k1 );
 $last = array_pop ( $keys );
 $node = $v;
 foreach ( $keys as $v2 ) {
  if (! isset ( $node->$v2 )) {
  $node->$v2 = new stdClass ();
  }
  $node = $node->$v2;
 }
 $node->$last = $v1;
 if (count ( $keys ) > 0) {
  unset ( $v->$k1 );
 }
 }
 
 /**
 * parseIni
 *
 * @param object $conf     
 * @return stdClass
 */
 private function parseIni($conf) {
 $confObj = new stdClass ();
 foreach ( $conf as $k => $v ) {
  // 是section
  if (is_array ( $v )) {
  $confObj->$k = ( object ) $v;
  foreach ( $v as $k1 => $v1 ) {
   call_user_func ( array (
    $this,
    'split' ), $confObj->$k, $k1, $v1 );
  }
  } else {
  call_user_func ( array (
   $this,
   'split' ), $confObj, $k, $v );
  }
 }
 unset ( $conf );
 // 处理继承
 foreach ( $confObj as $k => $v ) {
  if (false !== strpos ( $k, ':' )) {
  if (0 === strpos ( $k, ':' )) {
   throw new ErrorException ( 'config ' . $k . ' is invalid, ':' can't be the first char' );
  } elseif (1 < substr_count ( $k, ':' )) {
   throw new ErrorException ( 'config ' . $k . ' is invalid, ':' can appear only once' );
  } else {
   $keys = explode ( ':', $k );
   if (! isset ( $confObj->$keys [1] )) {
   throw new ErrorException ( 'parent section ' . $keys [1] . ' doesn't exist in config file' );
   } else {
   if (isset ( $confObj->$keys [0] )) {
    throw new ErrorException ( 'config is invalid, ' . $keys [0] . ' and ' . $k . ' conflicts' );
   } else {
    $confObj->$keys [0] = $this->deepCloneR ( $confObj->$keys [1] );
    $this->objectMergeR ( $confObj->$keys [0], $v );
    unset ( $confObj->$k );
   }
   }
  }
  }
 }
 return $confObj;
 }
 
 /**
 * php默认是浅克隆,函数实现深克隆
 *
 * @param object $obj     
 * @return object $obj
 */
 private function deepCloneR($obj) {
 $objClone = clone $obj;
 foreach ( $objClone as $k => $v ) {
  if (is_object ( $v )) {
  $objClone->$k = $this->deepCloneR ( $v );
  }
 }
 return $objClone;
 }
 
 /**
 * 递归的合并两个对象
 *
 * @param unknown $obj1     
 * @param unknown $obj2     
 */
 private function objectMergeR($obj1, $obj2) {
 foreach ( $obj2 as $k => $v ) {
  if (is_object ( $v ) && isset ( $obj1->$k ) && is_object ( $obj1->$k )) {
  $this->objectMergeR ( $obj1->$k, $v );
  } else {
  $obj1->$k = $v;
  }
 }
 }
}

简单使用:

$_ENV ['config'] = new Config ( file_get_contents ( __DIR__ . '/config.ini' ), array (
 'development' => array (
  'localhost.localdomain',
  'localhost'
 ),
 'production' => array ()
) );

配置文件示例:

[product]
db.default.dsn="mysql:host=127.0.0.1;dbname=default"
db.default.username=root
db.default.password=123456

admin.username=admin
admin.password=123456

php.error_reporting=E_ALL
php.display_errors=no
php.log_errors=yes
php.error_log=APP_PATH'/resource/log/phpError.log'
php.session.save_path=APP_PATH'/resource/data/session'

[development:product]
db.test1.dsn="mysql:host=127.0.0.1;dbname=test1"
db.test1.username=root
db.test1.password=123456
php.display_errors=yes
PHP 相关文章推荐
php 遍历显示文件夹下所有目录、所有文件的函数,没有分页的代码
Nov 14 PHP
一个简单的网页密码登陆php代码
Jul 17 PHP
教你如何解密 “ PHP 神盾解密工具 ”
Jun 20 PHP
Yii 快速,安全,专业的PHP框架
Sep 03 PHP
php跨站攻击实例分析
Oct 28 PHP
php通过执行CutyCapt命令实现网页截图的方法
Sep 30 PHP
PHP中SERIALIZE和JSON的序列化与反序列化操作区别分析
Oct 11 PHP
PHP 二维关联数组根据其中一个字段排序(推荐)
Apr 04 PHP
yii2局部关闭(开启)csrf的验证的实例代码
Jul 10 PHP
基于win2003虚拟机中apache服务器的访问
Aug 01 PHP
php输出控制函数和输出函数生成静态页面
Jun 27 PHP
php获取微信openid方法总结
Oct 10 PHP
PHP动态输出JavaScript代码实例
Feb 12 #PHP
PHP使用JSON和将json还原成数组
Feb 12 #PHP
服务器上配置PHP运行环境教程
Feb 12 #PHP
PHP保存带BOM文件的方法
Feb 12 #PHP
自己写的php curl库实现整站克隆功能
Feb 12 #PHP
PIGCMS 如何关闭聊天机器人
Feb 12 #PHP
PHP实现抓取Google IP并自动修改hosts文件
Feb 12 #PHP
You might like
php导出csv格式数据并将数字转换成文本的思路以及代码分享
2014/06/05 PHP
PHP登录验证功能示例【用户名、密码、验证码、数据库、已登陆验证、自动登录和注销登录等】
2019/02/25 PHP
一些常用的JS功能函数(2009-06-04更新)
2009/06/04 Javascript
JavaScript 学习笔记 Black.Caffeine 09.11.28
2009/11/30 Javascript
JS设置获取cookies的方法
2014/01/26 Javascript
javascript实现数字倒计时特效
2016/03/30 Javascript
AngularJS 模型详细介绍及实例代码
2016/07/27 Javascript
微信小程序中用WebStorm使用LESS
2017/03/08 Javascript
对存在JavaScript隐式类型转换的四种情况的总结(必看篇)
2017/08/31 Javascript
vue.js移动端app之上拉加载以及下拉刷新实战
2017/09/11 Javascript
微信小程序设置滚动条过程详解
2019/07/25 Javascript
浅析Vue 中的 render 函数
2020/02/28 Javascript
jQuery实现评论模块
2020/08/19 jQuery
[01:04:32]DOTA2-DPC中国联赛 正赛 Aster vs LBZS BO3 第二场 2月23日
2021/03/11 DOTA
基于Python如何使用AIML搭建聊天机器人
2016/01/27 Python
python获取当前用户的主目录路径方法(推荐)
2017/01/12 Python
用virtualenv建立多个Python独立虚拟开发环境
2017/07/06 Python
python自动发邮件总结及实例说明【推荐】
2019/05/31 Python
Python利用requests模块下载图片实例代码
2019/08/12 Python
妙用itchat! python实现久坐提醒功能
2019/11/25 Python
Python嵌套函数,作用域与偏函数用法实例分析
2019/12/26 Python
tensorflow实现打印ckpt模型保存下的变量名称及变量值
2020/01/04 Python
Python continue语句实例用法
2020/02/06 Python
Python 实现一个计时器
2020/07/28 Python
Marks & Spencer爱尔兰:英国马莎百货
2016/04/20 全球购物
美国最大点评网站:Yelp
2018/02/14 全球购物
LN-CC美国:伦敦时尚生活的缩影
2019/02/19 全球购物
SQL Server里面什么样的视图才能创建索引
2015/04/17 面试题
毕业生求职的求职信
2013/12/05 职场文书
迟到检讨书500字
2014/02/05 职场文书
群众路线个人对照检查材料
2014/09/23 职场文书
大学生村官个人对照检查材料(群众路线)
2014/09/26 职场文书
2016秋季校长开学典礼致辞
2015/11/26 职场文书
python-for x in range的用法(注意要点、细节)
2021/05/10 Python
Python 类,对象,数据分类,函数参数传递详解
2021/09/25 Python
Linux中如何安装并部署Redis
2022/04/18 Servers