问题:我正在尝试扩展 PHP 的 ArrayObject
,如下所示。不幸的是,在设置多维对象时我无法让它正常工作,而是抛出了一个错误,因为我在 PHP 中启用了严格设置。 (错误:严格标准:从空值创建默认对象
)
问题:如何修改我的类以自动为我创建不存在的关卡?
代码:
$config = new Config;
$config->lvl1_0 = true; // Works
$config->lvl1_1->lvl2 = true; // Throws error as "lvl1" isn't set already
class Config extends ArrayObject
{
function __construct() {
parent::__construct(array(), self::ARRAY_AS_PROPS);
}
public function offsetSet($k, $v) {
$v = is_array($v) ? new self($v) : $v;
return parent::offsetSet($k, $v);
}
}
最佳答案
从更 oop 的角度来看您的问题,您可以创建一个模拟多维对象概念的类。
我发布的解决方案并未从 ArrayObject
扩展以实现您提到的目标。当您将问题标记为 oop 时,我认为将存储对象状态的方式与访问对象的方式分开是很重要的。
希望这能帮助您实现所需!
根据您所说,多维对象是:
- 处理多层嵌套信息
- 它通过属性提供对信息的读/写访问来做到这一点
- 在访问未定义的属性时表现良好。这意味着,例如,您在空实例上执行以下操作:
$config->database->host = 'localhost'
database
和host
级别自动初始化,host
将在查询时返回'localhost'
。 - 理想情况下,将从关联数组初始化(因为您已经可以将配置文件解析到其中)
建议的解决方案
那么,如何实现这些功能呢?
第二个很简单:使用 PHP 的 __get
和 __set
方法。只要对不可访问的属性(未在对象中定义的属性)进行读/写操作,就会调用这些方法。
诀窍是不声明任何属性并通过这些方法处理属性的操作,并将作为键访问的属性名称映射到用作存储的关联数组。它们基本上会提供一个接口(interface),用于访问内部存储的信息。
对于第三个,我们需要一种方法来在读取未声明的属性时创建新的嵌套级别。
这里的关键点是认识到属性的返回值必须是一个多维对象,因此还可以从中创建更多级别的嵌套:每当我们询问其名称不存在于内部数组中的属性时,我们将该名称与 MultiDimensionalObject
的新实例相关联并返回它。返回的对象也将能够处理已定义或未定义的属性。
当一个未声明的属性被写入时,我们所要做的就是为其名称分配内部数组中提供的值。
第四个很简单(参见 __construct
实现)。我们只需确保在属性值为数组时创建 MultiDimensionalObject
。
最后,第一个:我们处理第二个和第三个特性的方式允许我们在任何级别的嵌套中读取和写入属性(声明的和未声明的)。
您可以在空实例上执行类似 $config->foo->bar->baz = 'hello'
的操作,然后查询 $config->foo->bar->baz
成功。
重要
请注意,MultiDimensionalObject
而不是 beign 本身是一个数组,它由一个数组组成,让您可以根据需要更改存储对象状态的方式。
实现
/* Provides an easy to use interface for reading/writing associative array based information */
/* by exposing properties that represents each key of the array */
class MultiDimensionalObject {
/* Keeps the state of each property */
private $properties;
/* Creates a new MultiDimensionalObject instance initialized with $properties */
public function __construct($properties = array()) {
$this->properties = array();
$this->populate($properties);
}
/* Creates properties for this instance whose names/contents are defined by the keys/values in the $properties associative array */
private function populate($properties) {
foreach($properties as $name => $value) {
$this->create_property($name, $value);
}
}
/* Creates a new property or overrides an existing one using $name as property name and $value as its value */
private function create_property($name, $value) {
$this->properties[$name] = is_array($value) ? $this->create_complex_property($value)
: $this->create_simple_property($value);
}
/* Creates a new complex property. Complex properties are created from arrays and are represented by instances of MultiDimensionalObject */
private function create_complex_property($value = array()){
return new MultiDimensionalObject($value);
}
/* Creates a simple property. Simple properties are the ones that are not arrays: they can be strings, bools, objects, etc. */
private function create_simple_property($value) {
return $value;
}
/* Gets the value of the property named $name */
/* If $name does not exists, it is initilialized with an empty instance of MultiDimensionalObject before returning it */
/* By using this technique, we can initialize nested properties even if the path to them don't exist */
/* I.e.: $config->foo
- property doesn't exists, it is initialized to an instance of MultiDimensionalObject and returned
$config->foo->bar = "hello";
- as explained before, doesn't exists, it is initialized to an instance of MultiDimensionalObject and returned.
- when set to "hello"; bar becomes a string (it is no longer an MultiDimensionalObject instance) */
public function __get($name) {
$this->create_property_if_not_exists($name);
return $this->properties[$name];
}
private function create_property_if_not_exists($name) {
if (array_key_exists($name, $this->properties)) return;
$this->create_property($name, array());
}
public function __set($name, $value) {
$this->create_property($name, $value);
}
}
演示
代码:
var_dump(new MultiDimensionalObject());
结果:
object(MultiDimensionalObject)[1]
private 'properties' =>
array
empty
代码:
$data = array( 'database' => array ( 'host' => 'localhost' ) );
$config = new MultiDimensionalObject($data);
var_dump($config->database);
结果:
object(MultiDimensionalObject)[2]
private 'properties' =>
array
'host' => string 'localhost' (length=9)
代码:
$config->database->credentials->username = "admin";
$config->database->credentials->password = "pass";
var_dump($config->database->credentials);
结果:
object(MultiDimensionalObject)[3]
private 'properties' =>
array
'username' => string 'admin' (length=5)
'password' => string 'pass' (length=4)
代码:
$config->database->credentials->username;
结果:
admin
关于php - 在 PHP 中正确扩展 ArrayObject?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7254675/