一个非常完美的读写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 相关文章推荐
PHP5/ZendEngine2的改进
Oct 09 PHP
mysql 全文搜索 技巧
Apr 27 PHP
PHP 将图片按创建时间进行分类存储的实现代码
Jan 05 PHP
在IIS7.0下面配置PHP 5.3.2运行环境的方法
Apr 13 PHP
解析php中用PHPMailer来发送邮件的示例(126.com的例子)
Jun 24 PHP
PHP中对于浮点型的数据需要用不同的方法解决
Mar 11 PHP
ThinkPHP实现带验证码的文件上传功能实例
Nov 01 PHP
php中current、next与reset函数用法实例
Nov 17 PHP
php给一组指定关键词添加span标签的方法
Mar 31 PHP
PHP实现163邮箱自动发送邮件
Mar 29 PHP
PHP生成二维码与识别二维码的方法详解【附源码下载】
Mar 07 PHP
php/JS实现的生成随机密码(验证码)功能示例
Jun 06 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模板引擎SMARTY
2006/10/09 PHP
自动生成文章摘要的代码[PHP 版本]
2007/03/20 PHP
php MsSql server时遇到的中文编码问题
2009/06/11 PHP
PHP把空格、换行符、中文逗号等替换成英文逗号的正则表达式
2014/05/04 PHP
PHP版本如何选择?应该使用哪个版本?
2015/05/13 PHP
64位windows系统下安装Memcache缓存
2015/12/06 PHP
js监听鼠标点击和键盘点击事件并自动跳转页面
2014/09/24 Javascript
基于jquery实现表格内容筛选功能实例解析
2016/05/09 Javascript
微信小程序 radio单选框组件详解及实例代码
2017/01/10 Javascript
jquery easyui dataGrid动态改变排序字段名的方法
2017/03/02 Javascript
Node做中转服务器转发接口
2017/10/18 Javascript
Angular实现可删除并计算总金额的购物车功能示例
2017/12/26 Javascript
JS实现显示当前日期的实例代码
2018/07/03 Javascript
vue添加axios,并且指定baseurl的方法
2018/09/19 Javascript
vue+element创建动态的form表单及动态生成表格的行和列
2019/05/20 Javascript
微信小游戏之使用three.js 绘制一个旋转的三角形
2019/06/10 Javascript
layer.confirm()右边按钮实现href的例子
2019/09/27 Javascript
实例分析javascript中的异步
2020/06/02 Javascript
Vue前端判断数据对象是否为空的实例
2020/09/02 Javascript
Python的Django框架中if标签的相关使用
2015/07/15 Python
python 实现在tkinter中动态显示label图片的方法
2019/06/13 Python
Python MongoDB 插入数据时已存在则不执行,不存在则插入的解决方法
2019/09/24 Python
Python实现屏幕录制功能的代码
2020/03/02 Python
pycharm导入源码的具体步骤
2020/08/04 Python
移动HTML5前端框架—MUI的使用
2017/12/18 HTML / CSS
个人应聘自我评价分享
2013/11/18 职场文书
西门豹教学反思
2014/02/04 职场文书
会展策划与管理专业大学生职业生涯规划
2014/02/07 职场文书
初三英语教学计划
2015/01/23 职场文书
机动车交通事故协议书
2015/01/29 职场文书
2015年药房工作总结
2015/04/25 职场文书
入党自传范文2015
2015/06/26 职场文书
“学党章、守党纪、讲党规”学习心得体会
2016/01/14 职场文书
2019年思想汇报
2019/06/20 职场文书
一次MySQL启动导致的事故实战记录
2021/09/15 MySQL
MySQL索引失效场景及解决方案
2022/07/23 MySQL