分享一个完善的读写ini格式的PHP配置类

分类:PHP_Python| 发布:佚名| 查看: | 发表时间:2015/8/10

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

* 解析.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读ini的类,分享一个完善的读写ini格式的PHP配置类相关推荐

  1. 分享一个好用的照片格式转换器方法

    如今信息技术的发展非常迅速,我们可以通过使用计算机来完成大部分工作.以前我们要查看图片,一般是打印的形式,现在多是在屏幕上查看图片.但是电脑图片其实有很多种格式,每种格式都有自己的特点和应用场景.有时 ...

  2. 分享一个超全的基于jedis的redis工具类

    以下为部分代码,完整的代码和redis应用实例,请移步到码云. 码云地址:  spring-boot-redis-case: 基于redisUtils的各种redis应用实例 ps:try-final ...

  3. .net工具类 分享一个简单的随机分红包的实现方式

    废话不多说,直接上代码 /// <summary>/// 分红包/// </summary>public class RandomMoney{public RandomMone ...

  4. android 网络图片工具类,分享一个Android图片模糊的工具类

    图片模糊,试过很多工具什么的,还是这个类比较好,直接用就好了 使用方法: imageView.setImageBitmap(BlurUtil.doBlur(drawable,10,15)); pack ...

  5. 再分享一个自己写的向量和二维坐标变换的类

    使用方法如下: Matrix2D matrix2D = new Matrix2D(m_CADCooridate, m_OtherCooridateInfo.CADCooridate, m_SDRQCo ...

  6. 【Android应用开发】分享一个录制 Android 屏幕 gif 格式的小技巧

    因为写博客总是需要录制 Android 软件的演示效果, 研究了将近一小时找到了合适的工具; 录制流程 : -- 1. 录制 Android 手机屏幕内容 : 使用 拍大师 软件录制 Android ...

  7. c dbhelper类下载mysql_分享一个简单的C#的通用DbHelper类(支持数据连接池)

    每次新项目的时候,都要从头去找一遍数据库工具类.这里分享一个简单实用的C#的通用DbHelper工具类,支持数据连接池. 连接池配置 DbHelper类 public classDBHelper { ...

  8. 从0搭建一个Springboot+vue前后端分离项目(六)后台编写配置类与接口

    新建一个包,里面放入一些常用的配置类 引入mybatis-plus包与插件 引入包 前往官网查看 https://baomidou.com/pages/226c21/#%E5%88%9D%E5%A7% ...

  9. java一个包有两个类_java一个包包含多个类 java 类包含类

    一个java工程可以有多个包含main方法的类吗? 每一个java文件都会有一个public static void main(String[] args)作为程序作为入口,一个类有且只有一个,但是可 ...

最新文章

  1. tree view 後台編寫
  2. 基于socket的C语言编程,C语言实现的Socket编程
  3. .NET 6 Preview 4 已发布,这些新功能值得关注!
  4. 如何使用putExtra()和getExtra()来表示字符串数据
  5. iOS之获取设备的UUID
  6. 订阅github release(官方+IFTTT)
  7. 数据库系统基础教程(1)数据库系统世界
  8. 阿里云盘下载安装保存文件教程
  9. Drools(BRMS) 速成教程(上)
  10. snipaste怎么滚动截长图_还在用老方法截长图?分享iPhone滚动截屏方法,无需拼接1秒出图...
  11. MFC中有关鼠标单击双击响应的问题
  12. 苹果商城怎么调成中文_使用苹果手机时,你感觉最不舒服的地方有哪些?
  13. 一个ios工程师必须具备的八大知识技能点
  14. MySQL查看表结构SQL语句
  15. 条件自信息量与互信息量的区别
  16. SpringBoot如何上传大文件
  17. 全自动过滤器:全自动管道过滤器工作原理
  18. Logstash:如何使用 Logstash Grok 过滤器提取模式
  19. 企业费控,驶向「一体化」
  20. 首席新媒体黎想教程:一份完整的运营方案,应包含的7个方面

热门文章

  1. 其实男人需要这样的女人,全天下男人的真心告白!
  2. 炫酷水球图:让数据可视化更生动有趣
  3. STM32F103ZE点灯
  4. 400Bad Request异常
  5. 020:Mapbox GL加载高德地图(影像瓦片图)
  6. 内网代理的系列二:frp(socks5)+Proxifier
  7. localStorage数据缓存
  8. First order logic——Inference
  9. 本地AC在线WA?RE?来个栗子帮助你。
  10. 字典特征提取DictVectorizer(特征工程之特征提取)