从零开始编写一个PHP框架 系列的《配置模块》
项目地址:terse
前言
一个扩展性、兼容性强的项目,其可配性肯定很强。
需求分析
- 可以单个配置
- 可以批量配置
- 可以转换成数组
配置
先看一下配置后,类的输出。
object(Terse\Config)#17 (1) {
["memcached"]=>
object(Terse\Config)#18 (2) {
["lifetime"]=>
int(2592000)
["server"]=>
object(Terse\Config)#19 (2) {
["host"]=>
string(9) "memcached"
["port"]=>
int(11211)
}
}
}
需要继承的类
这里为了方便使用数组的方式操作配置,所以需要继承 ArrayAccess
接口。
同时,数组一般少不了 count
,于是又继承了 Countable
接口。
这里根据具体情况可以进行取舍。
初始化类
通过官方文档可以看出,在继承接口 ArrayAccess
和 Countable
之后,这里需要实现几个方法:
public function count();
public function offsetExists($key);
public function offsetGet($key);
public function offsetSet($key, $value);
public function offsetUnset($key);
设置
这里准备将数组的每个键作为类的属性,比如:
/**
* 添加配置
*
* @param string $key
* @param mixed $value
*/
public function set($key, $value)
{
$this->{$key} = $value;
}
不过,为了统一,在设置时,直接调用 offsetSet
方法,这样在用数组方式赋值时,也会成功。
/**
* 添加配置
*
* @param string $key
* @param mixed $value
*/
public function set($key, $value)
{
$this->offsetSet($key, $value);
}
同样的,如果时批量设置,我们只需要给个循环就OK:
/**
* 批量添加配置
*
* @param array $params
*/
public function batchSet(array $params)
{
foreach ($params as $key => $value) {
$this->offsetSet($key, $value);
}
}
获取
类似设置,在获取时,需要用到 offsetExists
和 offsetGet
两个方法,主要是做一个是否存在的检测。
当然,为了使获取功能更加人性化,我们设置了默认值的选项。
/**
* 获取某个配置
*
* @param string $key
* @param mixed $default
* @return mixed
*/
public function get($key, $default = null)
{
if (!$this->offsetExists($key)) {
return $default;
}
return $this->offsetGet($key);
}
统计
有了设置和获取,那么就可以计算出当前配置类里又多少个键值了。
/**
* 总计
*
* @return int
*/
public function count()
{
return count(get_object_vars($this));
}
完善接口方法
是否存在:
/**
* ArrayAccess offsetExists
*
* @param string $key
* @return bool
*/
public function offsetExists($key)
{
$key = (string)$key;
return isset($this->{$key});
}
获取:
/**
* ArrayAccess offsetGet
*
* @param string $key
* @return mixed
*/
public function offsetGet($key)
{
$key = (string)$key;
if (!$this->offsetExists($key)) {
return null;
}
return $this->{$key};
}
销毁:
/**
* ArrayAccess offsetUnset
*
* @param string $key
*/
public function offsetUnset($key)
{
if ($this->offsetExists($key)) {
unset($this->{$key});
}
}
上述的几个方法都很简单,一下子就能看懂,而唯独少了设置的实现。
之所以要把设置单独拿出来,不是因为设置有多麻烦,而是在做的时候,思考过一个问题:先实例化再设置,还是在实例化的时候就设置的问题。
最终,我选择了后者,在实例化的时候就设置。
所以,在构造函数里,我们就需要进行一个批量设置:
/**
* 配置初始化
*
* @param array $configArr
*/
public function __construct(array $configArr)
{
if (!$configArr) {
return true;
}
foreach ($configArr as $key => $value) {
$this->offsetSet($key, $value);
}
}
那么,在 offsetSet
方法里,也需要对 $value
进行判断,毕竟我们不确定用户配置的是一维数组还是多维数组。
/**
* ArrayAccess offsetSet
*
* @param string $key
* @param mixed $value
*/
public function offsetSet($key, $value)
{
$key = (string)$key;
if (is_array($value)) {
$this->{$key} = new self($value);
return true;
}
$this->{$key} = $value;
}
转数组
说实话,这个功能有点冗余,毕竟正常情况下用不到,而且,我们基本实现了数组的一些常用功能。
这里用了一个循环,其实主要也是看 $value
是类还是字符串之类的,然后看看是否调用 toArray()
方法。
/**
* 转换成数组
*
* @return array
*/
public function toArray()
{
$params = get_object_vars($this);
$configArr = [];
foreach ($params as $key => $param) {
if ($param instanceof self && method_exists($param, 'toArray')) {
$configArr[$key] = $param->toArray();
continue;
}
$configArr[$key] = $param;
}
return $configArr;
}
到此为止,配置类编写结束。
完整代码
<?php
namespace Terse;
/**
* Terse\Config
*
* @link https://gitee.com/imjcw/terse
* @author imjcw <imjcw@imjcw.com>
*/
class Config implements \ArrayAccess, \Countable
{
/**
* 配置初始化
*
* @param array $configArr
*/
public function __construct(array $configArr)
{
if (!$configArr) {
return true;
}
foreach ($configArr as $key => $value) {
$this->offsetSet($key, $value);
}
}
/**
* 检查某个配置是否存在
*
* @param string $key
* @return boolean
*/
public function has($key)
{
return $this->offsetExists($key);
}
/**
* 获取某个配置
*
* @param string $key
* @param mixed $default
* @return mixed
*/
public function get($key, $default = null)
{
if (!$this->offsetExists($key)) {
return $default;
}
return $this->offsetGet($key);
}
/**
* 添加配置
*
* @param string $key
* @param mixed $value
*/
public function set($key, $value)
{
$this->offsetSet($key, $value);
}
/**
* 批量添加配置
*
* @param array $params
*/
public function batchSet(array $params)
{
foreach ($params as $key => $value) {
$this->offsetSet($key, $value);
}
}
/**
* 转换成数组
*
* @return array
*/
public function toArray()
{
$params = get_object_vars($this);
$configArr = [];
foreach ($params as $key => $param) {
if ($param instanceof self && method_exists($param, 'toArray')) {
$configArr[$key] = $param->toArray();
continue;
}
$configArr[$key] = $param;
}
return $configArr;
}
/**
* 总计
*
* @return int
*/
public function count()
{
return count(get_object_vars($this));
}
/**
* ArrayAccess offsetExists
*
* @param string $key
* @return bool
*/
public function offsetExists($key)
{
$key = (string)$key;
return isset($this->{$key});
}
/**
* ArrayAccess offsetGet
*
* @param string $key
* @return mixed
*/
public function offsetGet($key)
{
$key = (string)$key;
if (!$this->offsetExists($key)) {
return null;
}
return $this->{$key};
}
/**
* ArrayAccess offsetSet
*
* @param string $key
* @param mixed $value
*/
public function offsetSet($key, $value)
{
$key = (string)$key;
if (is_array($value)) {
$this->{$key} = new self($value);
return true;
}
$this->{$key} = $value;
}
/**
* ArrayAccess offsetUnset
*
* @param string $key
*/
public function offsetUnset($key)
{
if ($this->offsetExists($key)) {
unset($this->{$key});
}
}
}
结语
配置模块是一系列模块中比较简单的模块,但也是比较重要的模块,毕竟项目的配置还是需要它来提供的。
下一篇:《日志模块》