一个非常完美的读写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 相关文章推荐
一个取得文件扩展名的函数
Oct 09 PHP
无JS,完全php面向过程数据分页实现代码
Aug 27 PHP
网页上facebook分享功能具体实现
Jan 26 PHP
php集成环境xampp中apache无法启动问题解决方案
Nov 18 PHP
php查询mysql大量数据造成内存不足的解决方法
Mar 04 PHP
FastCGI 进程意外退出造成500错误
Jul 26 PHP
thinkPHP中钩子的两种配置调用方法详解
Nov 11 PHP
PHPMailer发送邮件
Dec 28 PHP
php 如何设置一个严格控制过期时间的session
May 05 PHP
thinkPHP5框架设置404、403等http状态页面的方法
Jun 05 PHP
PHP实现chrome表单请求数据转换为接口使用的json数据
Mar 04 PHP
PHP遍历数组的6种方式总结
Nov 17 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下使用curl模拟用户登陆的代码
2010/09/10 PHP
php格式化json函数示例代码
2016/05/12 PHP
php中的单引号、双引号和转义字符详解
2017/02/16 PHP
Highslide.js是一款基于js实现的网页中图片展示插件
2020/03/30 Javascript
JavaScript Event学习第九章 鼠标事件
2010/02/08 Javascript
js中eval()函数和trim()去掉字符串左右空格应用
2013/02/02 Javascript
js设置组合快捷键/tabindex功能的方法
2013/11/21 Javascript
深入了解Node.js中的一些特性
2014/09/25 Javascript
JavaScript常用脚本汇总(三)
2015/03/04 Javascript
使用JavaScript制作一个简单的计数器的方法
2015/07/07 Javascript
Node.js环境下编写爬虫爬取维基百科内容的实例分享
2016/06/12 Javascript
简单实现node.js图片上传
2016/12/18 Javascript
jQuery中on方法使用注意事项详解
2017/02/15 Javascript
BootStrap表单宽度设置方法
2017/03/10 Javascript
Element输入框带历史查询记录的实现示例
2019/01/15 Javascript
微信小程序如何调用json数据接口并解析
2019/06/29 Javascript
微信公众号获取用户地理位置并列出附近的门店的示例代码
2019/07/25 Javascript
python实现判断数组是否包含指定元素的方法
2015/07/15 Python
完美解决python遍历删除字典里值为空的元素报错问题
2016/09/11 Python
python unittest实现api自动化测试
2018/04/04 Python
python3常用的数据清洗方法(小结)
2019/10/31 Python
使用wxpy实现自动发送微信消息功能
2020/02/28 Python
python实现最速下降法
2020/03/24 Python
Python web如何在IIS发布应用过程解析
2020/05/27 Python
Python基于traceback模块获取异常信息
2020/07/23 Python
Pycharm学生免费专业版安装教程的方法步骤
2020/09/24 Python
全球精选男装和家居用品:Article
2020/04/13 全球购物
大学生励志演讲稿
2014/04/25 职场文书
物业品质提升方案
2014/06/08 职场文书
党员先进性教育整改措施
2014/09/18 职场文书
中学生社区服务活动报告
2015/02/05 职场文书
2015高考寄语集锦
2015/02/27 职场文书
2016大学生社会实践心得体会范文
2016/01/14 职场文书
《游戏公平》教学反思
2016/02/20 职场文书
Redis Cluster 字段模糊匹配及删除
2021/05/27 Redis
Pyhton爬虫知识之正则表达式详解
2022/04/01 Python