使用Zend_Config让用户自定义应用程序配置

Author Avatar
在路上 12月 25, 2011

Zend_Config是Zend Framework的一个组件,Zend_Config可以读写数组、INI、XML格式的文件。

XML

我们先看一个XML的例子:

XML文件:config.xml

1
2
3
4
5
6
7
8
9
<?xml version='1.0'?>
<config>
<dialer>
<number>12345678</number>
<retries>15</retries>
<protocol>ppp</protocol>
</dialer>
</config>

下面看下Zend_Config是怎么访问这个XML文件的数据的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
// include auto-loader class
require_once 'Zend/Loader/Autoloader.php';
// register auto-loader
$loader = Zend_Loader_Autoloader::getInstance();
// read XML config file
$config = new Zend_Config_Xml('config.xml', 'dialer');
// access individual nodes
printf("Number: %s \r\n", $config->number);
printf("Retries: %s \r\n", $config->retries);
printf("Protocol: %s \r\n", $config->protocol);
?>

其中,Zend_Loader_Autoloader可以自动加载我们要使用的Zend Framework 组件类,如Zend_Config_Xml。 我们可以使用Zend_Config,也可以使用Zend_Config的子类操作配置文件: 包括Zend_Config_Xml、Zend_Config_Ini、Zend_Config_Json、Zend_Config_Yaml, 如果要操作数组,我们可以直接使用Zend_Config. 上面的代码使用了Zend_Config_Xml,我们看下Zend_Config_Xml的构造方法:

1
2
3
4
__construct( string $xml, //XML字符串或XML文件名
mixed $section = null, //开始解析的XML节点
array|boolean $options = false //设置是否允许修改该XML
) : void

对于构造方法的第三个参数,需要强调一点: 如果该参数为boolean类型,即true或false,则等价于

1
$options = array( 'allowModifications' => false

如果该参数为数组,其形式为

1
$options = array( 'allowModifications' => false, 'skipExtends' => false );

不理解skipExtends的作用。

  • 从构造方法里可以看出,后两个参数是可选的:*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
// include auto-loader class
require_once 'Zend/Loader/Autoloader.php';
// register auto-loader
$loader = Zend_Loader_Autoloader::getInstance();
// read XML config file
$config = new Zend_Config_Xml('config.xml');
// access individual nodes
printf("Number: %s \r\n", $config->dialer->number);
printf("Retries: %s \r\n", $config-> dialer->retries);
printf("Protocol: %s \r\n", $config-> dialer->protocol);
?>

在上面的XML文件里,我们发现这些节点都没有属性,如果节点有属性,Zend_Config_Xml是怎么处理的呢?

1
2
3
4
5
6
7
8
<?xml version='1.0'?>
<config>
<firewall context="default" access="deny" >
<rule access="allow" network="10.0.0.0/8" />
<rule access="allow" host="192.168.1.17" />
</firewall>
</config>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
// include auto-loader class
require_once 'Zend/Loader/Autoloader.php';
// register auto-loader
$loader = Zend_Loader_Autoloader::getInstance();
// read XML config file
$config = new Zend_Config_Xml('config.xml', 'firewall');
// returns 'default'
echo $config->context;
// returns 'allow'
echo $config->rule->{0}->access;
// returns '192.168.1.17'
echo $config->rule->{1}->host;
?>

可以看出,节点的属性也将作为子节点处理,注意rule标签的访问,可以使用{0}、{1}分别访问rule标签。

读取INI文件

INI文件:config.ini

1
2
3
4
[dialer]
number = 12345678
retries = 15
protocol = ppp

1
2
3
4
5
6
7
8
9
<?php
// read XML config file
$config = new Zend_Config_Ini('config.ini', 'dialer');
// access individual elements
printf("Number: %s \r\n", $config->number);
printf("Retries: %s \r\n", $config->retries);
printf("Protocol: %s \r\n", $config->protocol);
?>

读取数组:config.php

1
2
3
4
5
6
7
8
9
<?php
return $config = array(
'dialer' => array(
'number' => 12345678,
'retries' => 15,
'protocol' => 'ppp'
)
);
?>

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
// include PHP configuration data
require_once 'config.php';
// read XML config file
$config = new Zend_Config($config);
// access individual elements
printf("Number: %s \r\n", $config->dialer->number);
printf("Retries: %s \r\n", $config->dialer->retries);
printf("Protocol: %s \r\n", $config->dialer->protocol);
?>

使用数组的优点: APC等PHP opcode cache可以缓冲这些数据,减少文件读操作,这样可以改善性能。

读取yaml

参考two approaches which make use of the syck extension and the spyc library

读取多层嵌套的配置文件

config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version='1.0'?>
<configs>
<config scope="php">
<filters>
<filter name="Tidy">
<parameters name="tidy_options">
<parameter>
<name>output-xhtml</name>
<value>true</value>
</parameter>
<parameter>
<name>numeric-entities</name>
<value>true</value>
</parameter>
<parameter>
<name>encoding</name>
<value>utf8</value>
</parameter>
</parameters>
</filter>
</filters>
</config>
</configs>

1
2
3
4
5
6
7
8
<?php
// read XML config file
$config = new Zend_Config_Xml('config.xml', 'config');
// returns 'true'
echo $config->filters->filter->parameters->parameter->{0}->value;
?>

Zend_Config实现了迭代器,Iterator interface,所以可以迭代访问配置数据

1
2
3
4
5
6
7
8
9
10
<?php
// read XML config file
$config = new Zend_Config_Xml('config.xml', 'config');
// iterate over parameters
foreach ($config->filters->filter->parameters->parameter as $p) {
printf("%s = %s \r\n", $p->name, $p->value);
}
?>

配置之间可以继承

XML使用extends属性,指定要继承的节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version='1.0'?>
<configs>
<default>
<log>
<filename>general.log</filename>
<data>time,message,code</data>
<maxsize>2M</maxsize>
</log>
</default>
<error extends="default">
<log>
<filename>error.log</filename>
</log>
</error>
</configs>

1
2
3
4
5
6
7
8
9
10
11
<?php
// define Zend_Config objects
$config = new Zend_Config_Xml('config.xml');
// returns 'error.log'
echo $config->error->log->filename;
// returns '2M'
echo $config->error->log->maxsize;
?>

INI使用colon冒号指定继承关系,回忆下Zend Framework工程文件中的配置文件application.ini

1
2
3
4
5
6
7
[default]
log.filename = "general.log"
log.data = "time,message,code"
log.maxsize = "2M"
[error : default]
log.filename = "error.log"

我们还可以将配置文件分成多个配置文件,新的数据将覆盖原来的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// define Zend_Config objects
$zca = new Zend_Config(array('a'=>10, 'b'=>2), true);
$zcb = new Zend_Config(array('c'=>4, 'b'=>16), true);
// merge objects
$zca->merge($zcb);
// check merged data
echo $zca->a; // 10
echo $zca->b; // 16
echo $zca->c; // 4
?>

配置文件的写操作

使用Zend_Config_Writer可以操作INI、XML、PHP Array。 INI举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
// define configuration array
$data = array(
'name' => 'Zerg Ultralisk',
'endurance' => '7',
'strength' => '13',
'intelligence' => '8',
'damage' => '4'
);
// write INI config file
try {
$config = new Zend_Config_Writer_Ini();
$config->write('my.ini', new Zend_Config($data));
echo 'Configuration successfully written to file.';
} catch (Exception $e) {
die('ERROR: ' . $e->getMessage());
}
?>

我们使用Zend_Config_Writer_Ini的write()方法将$data写入my.ini文件。

要将配置数据写入XML文件,只需使用Zend_Config_Writer_Xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
// define configuration array
$data = array(
'name' => 'Zerg Ultralisk',
'endurance' => '7',
'strength' => '13',
'intelligence' => '8',
'damage' => '4'
);
// write XML config file
try {
$config = new Zend_Config_Writer_Xml();
$config->write('my.xml', new Zend_Config($data));
echo 'Configuration successfully written to file.';
} catch (Exception $e) {
die('ERROR: ' . $e->getMessage());
}
?>

同样,我们也可以将配置数据写入php文件,使用PHP array保存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
// define configuration array
$data = array(
'name' => 'Zerg Ultralisk',
'endurance' => '7',
'strength' => '13',
'intelligence' => '8',
'damage' => '4'
);
// write array config file
try {
$config = new Zend_Config_Writer_Array();
$config->write('my.php', new Zend_Config($data));
echo 'Configuration successfully written to file.';
} catch (Exception $e) {
die('ERROR: ' . $e->getMessage());
}
?>

创建嵌套的XML配置文件

使用数组初始化Zend_Config:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
// define configuration array
$data = array(
'global' => array(
'smtp' => array(
'parameters' => array(
'host' => 'smtp.example.com',
'port' => '587',
'username' => 'jeky11',
'password' => 'hyd3',
'security' => 'tls',
)
)
)
);
// write XML config file
try {
$config = new Zend_Config_Writer_Xml();
$config->write('my.xml', new Zend_Config($data));
echo 'Configuration successfully written to file.';
} catch (Exception $e) {
die('ERROR: ' . $e->getMessage());
}
?>

使用object->property初始化Zend_Config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!--?php // define configuration array $data = array( 'global' =--> array(
'smtp' => array(
'parameters' => array(
'host' => 'smtp.example.com',
'port' => '587',
'username' => 'jeky11',
'password' => 'hyd3',
'security' => 'tls',
)
)
)
);
// write XML config file
try {
$config = new Zend_Config_Writer_Xml();
$config->write('my.xml', new Zend_Config($data));
echo 'Configuration successfully written to file.';
} catch (Exception $e) {
die('ERROR: ' . $e->getMessage());
}
?>

创建嵌套的INI配置文件

使用SetNestSeparator()设置嵌套的分隔符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
// define configuration array
$data = array(
'global' => array(
'smtp' => array(
'parameters' => array(
'host' => 'smtp.example.com',
'port' => '587',
'username' => 'jeky11',
'password' => 'hyd3',
'security' => 'tls',
)
)
),
'local' => array(
'version' => '1.1'
)
);
// write INI config file
try {
$config = new Zend_Config_Writer_Ini();
$config->setNestSeparator('::');
$config->write('my.ini', new Zend_Config($data));
echo 'Configuration successfully written to file.';
} catch (Exception $e) {
die('ERROR: ' . $e->getMessage());
}
?>

使用setRenderWithoutSections() 将INI文件分为多个模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
// include auto-loader class
require_once 'Zend/Loader/Autoloader.php';
// register auto-loader
$loader = Zend_Loader_Autoloader::getInstance();
// define configuration array
$data = array(
'global' => array(
'smtp' => array(
'parameters' => array(
'host' => 'smtp.example.com',
'port' => '587',
'username' => 'jeky11',
'password' => 'hyd3',
'security' => 'tls',
)
)
),
'local' => array(
'version' => '1.1'
)
);
// write INI config file
try {
$config = new Zend_Config_Writer_Ini();
$config->setNestSeparator('::');
$config->setRenderWithoutSections(true);
$config->write('my.ini', new Zend_Config($data));
echo 'Configuration successfully written to file.';
} catch (Exception $e) {
die('ERROR: ' . $e->getMessage());
}
?>

相关文章:应用Zend_Config创建一个用户可以自定义的Task Manager(任务管理应用)

参考:

2017-08-27 整理