一个非常完美的读写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 相关文章推荐
DedeCms模板安装/制作概述
Mar 11 PHP
fleaphp下不确定的多条件查询的巧妙解决方法
Sep 11 PHP
Ext.data.PagingMemoryProxy分页一次性读取数据的实现代码
Apr 07 PHP
Pain 全世界最小最简单的PHP模板引擎 (普通版)
Oct 23 PHP
cakephp打印sql语句的方法
Feb 13 PHP
简单介绍PHP的责任链编程模式
Aug 11 PHP
phpinfo() 中 Local Value(局部变量)Master Value(主变量) 的区别
Feb 03 PHP
php如何实现不借助IDE快速定位行数或者方法定义的文件和位置
Jan 17 PHP
php 基础函数
Feb 10 PHP
PHPMailer ThinkPHP实现自动发送邮件功能
Jun 10 PHP
PHP设计模式之装饰器模式定义与用法简单示例
Aug 13 PHP
php精度计算的问题解析
Jun 21 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实现根据url自动生成缩略图的方法
2014/09/23 PHP
PHP封装的字符串加密解密函数
2015/12/18 PHP
php获取本机真实IP地址实例代码
2016/03/31 PHP
详解EventDispatcher事件分发组件
2016/12/25 PHP
php设计模式之策略模式实例分析【星际争霸游戏案例】
2020/03/26 PHP
Jquery拖拽并简单保存的实现代码
2010/11/28 Javascript
深入理解JavaScript高级之词法作用域和作用域链
2013/12/10 Javascript
一个奇葩的最短的 IE 版本判断JS脚本
2014/05/28 Javascript
jquery实现右键菜单插件
2015/03/29 Javascript
javascript生成随机数方法汇总
2015/11/12 Javascript
最简单的JavaScript图片轮播代码(两种方法)
2015/12/18 Javascript
Google Maps基础及实例解析
2016/08/06 Javascript
前端面试题及答案整理(二)
2016/08/26 Javascript
原生javascript移动端滑动banner效果
2017/03/10 Javascript
使用vue-cli编写vue插件的方法
2018/02/26 Javascript
vue2过滤器模糊查询方法
2018/09/16 Javascript
微信小程序实现多选功能
2018/11/04 Javascript
使用原生javascript开发计算器实例代码
2021/02/21 Javascript
Python中动态获取对象的属性和方法的教程
2015/04/09 Python
pycharm中连接mysql数据库的步骤详解
2017/05/02 Python
利用Python循环(包括while&amp;for)各种打印九九乘法表的实例
2017/11/06 Python
Django教程笔记之中间件middleware详解
2018/08/01 Python
Python构建图像分类识别器的方法
2019/01/12 Python
python 使用matplotlib 实现从文件中读取x,y坐标的可视化方法
2019/07/04 Python
HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题
2021/01/19 HTML / CSS
英国皇家造币厂:The Royal Mint
2018/10/05 全球购物
什么是跨站脚本攻击
2014/12/11 面试题
中学生期末评语
2014/02/03 职场文书
交通事故调解协议书
2014/04/16 职场文书
课前三分钟演讲稿
2014/04/24 职场文书
学习雷锋精神演讲稿
2014/05/10 职场文书
应届毕业生求职信范文
2014/07/07 职场文书
食品科学与工程专业毕业生求职信范文
2014/07/21 职场文书
安全生产隐患排查制度
2015/08/05 职场文书
浅谈MySQL next-key lock 加锁范围
2021/06/07 MySQL
MYSQL中文乱码问题的解决方案
2022/06/14 MySQL