在PHP扩展ArrayObject的正确? [英] Extending ArrayObject in PHP properly?

查看:292
本文介绍了在PHP扩展ArrayObject的正确?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:我试图延长PHP的 ArrayObject的,如下图所示。不幸的是我不能设置多维对象,而是抛出我在PHP中启用了严格的设置错误时,它才能正常工作。 (错误:严格的标准:创建从空值,默认对象

问:如何修改我的课为我自动创建不存在的水平

的code:

$配置=新配置;
组$ config-> lvl1_0 = TRUE; //作品
组$ config-> lvl1_1-> LVL2 = TRUE; //抛出错误为LVL1尚未设置,类配置扩展ArrayObject的
{
    功能__construct(){
        父:: __结构(阵列(),自:: ARRAY_AS_PROPS);
    }    公共职能offsetSet($ K,$ V){
        $ V = is_array($ V)?新的自($ V):$ V;
        返回父:: offsetSet($ K,$ V);
    }
}


解决方案

以你的问题更多的空中接力视图,您可以创建一个类,模型的多维对象的概念。

解决方案IM发布不会从 ArrayObject的延伸到archieve你提到的目标。当你标记为您的空中接力的问题,我认为重要的汇入作业,加强分离从你怎么访问你存储对象的状态的方式。

希望这会帮助你archieve你所需要的!

这是你说的,一个多维的对象是一个:


  • 处理的嵌套的多级信息

  • 它通过提供读/通过属性写入信息访问这样做

  • 在当前不确定的属性被访问表现很好。这意味着,例如,你的上一个空的实例如下:组$ config->数据库 - >主机='localhost'的数据库主机水平自动初始化,而主机将返回查询时的'localhost'

  • 理想情况下,会从关联数组初始化(因为你已经可以解析配置文件放进去)

建议的解决方案

那么,怎样才能这些功能来实现?

第二个很简单:使用PHP的 __ GET __设置方法。每当读/写操作beign上inaccesible财产(这是不是一个对象定义的一个)来完成这些将被调用。
诀窍会那么不申报任何财产,并通过这些方法处理propertie的运营和映射属性名beign accesed作为重点作为一个存储阵列assosiative。他们会为accesing内部存储的信息基本上提供一个接口。

有关第三个,我们需要一种方法时,未申报财产readed创建一个新的嵌套级别。
这里的关键点认识到该属性的返回的值一定是这样的嵌套进一步水平可以从它也可以创建一个多维目标:每当we're问其名的属性不是在present内部数组,我们就会说名 MultiDimensionalObject 的新实例相关联,并将其返回。返回的对象将能处理过定义或未定义的属性。

在未申报的财产被写入时,我们所要做的就是赋予它的名字与内部数组中提供的值。

第四个是容易的(看到它在 __构建实现)。我们只需要确保我们创建一个 MultiDimensionalObject 当一个属性的值是一个数组。

最后,拳之一:我们处理的第二个和第三个特点的方式让我们能够读取和写入性能(申报未申报和)在任何级别的嵌套。
你可以做这样的事情组$ config-> foo->酒吧,>巴兹='你好'上一个空实例,然后查询组$ config-> foo->酒吧,方式>巴兹成功

重要
请注意, MultiDimensionalObject 代替的 beign 的本身是一个数组是它的的一个数组,让你改变你的存储方式根据需要将对象的状态。

实施

  / *提供一个易于使用的界面,用于读取/写入关联数组基础的信息* /
/ *通过暴露了重新presents数组中的每个关键属性* /
类MultiDimensionalObject {    / *保持每个属性的状态* /
    私人$性能;    / *创建一个具有$属性初始化的新MultiDimensionalObject实例* /
    公共职能__construct($性能=阵列()){
        $这个 - >性能=阵列();
        $这个 - >填充($属性);
    }    / *创建属性此实例,其名称/内容由密钥/值$属性关联数组中定义* /
    私有函数填充($属性){
        的foreach($属性$名=> $值){
            $这个 - > create_property($名称,$值);
        }
    }    / *创建一个新的属性或使用$名称作为属性名称和$值作为其值将覆盖现有的* /
    私有函数create_property($名称,$值){
        $这个 - >性能[$名称] = is_array($值)? $这个 - > create_complex_property($值)
                                                    函数:$ this-> create_simple_property($值);
    }    / *创建一个新的复杂属性。复杂的属性从阵列创建,并重新通过MultiDimensionalObject的实例psented $ P $ * /
    私有函数create_complex_property($值=阵列()){
        返回新MultiDimensionalObject($值);
    }    / *创建一个简单的属性。简单的属性是不是数组中的:他们可以是字符串,布尔变量,对象等* /
    私有函数create_simple_property($值){
        返回$价值;
    }    / *获取属性名为$ name的值* /
    / *如果$名称不存在,它返回它之前initilialized与MultiDimensionalObject的空实例* /
    / *通过使用该技术,我们可以即使路径它们不存在*初始化嵌套属性/
    / *即:组$ config->富
                     - 属性不存在,它被初始化为MultiDimensionalObject的一个实例,并返回             组$ config-> foo->巴=你好;
                     - 如前所述,不存在,它被初始化为MultiDimensionalObject的实例并返回。
                     - 当设置为Hello;酒吧就成了一个字符串(它不再是一个MultiDimensionalObject实例)* /
    公共职能__get($名){
        $这个 - > create_property_if_not_exists($名);
        返回$这个 - >性能[$名称];
    }    私有函数create_property_if_not_exists($名){
        如果(array_key_exists($名称,$这个 - >属性))回报;
        $这个 - > create_property($名称,阵列());
    }    公共职能__set($名称,$值){
        $这个 - > create_property($名称,$值);
    }
}

演示

code:
    后续代码var_dump(新MultiDimensionalObject());

结果:

 对象(MultiDimensionalObject)[1]
    私人属性= GT;
        排列
            空

code:

  $数据=阵列('数据库'=>阵列('主机'=>的'localhost'));
$配置=新MultiDimensionalObject($的数据);
后续代码var_dump(组$ config->数据库);

结果:

 对象(MultiDimensionalObject)[2]
    私人属性= GT;
        排列
            '主机'= GT;字符串'localhost'的(长度= 9)

code:

 组$ config->数据库 - > credentials->用户名=admin的;
组$ config->数据库 - > credentials->密码=通行证;
后续代码var_dump(组$ config->数据库 - >凭证);

结果:

 对象(MultiDimensionalObject)[3]
    私人属性= GT;
        排列
          用户名= GT;字符串管理员(长度= 5)
          '密码'=>字符串'通行证'(长度= 4)

code:

 组$ config->数据库 - > credentials->用户名;

结果:

 管理

Problem: I am trying to extend PHP's ArrayObject as shown below. Unfortunately I can't get it to work properly when setting multi-dimensional objects and instead an error thrown as I have the strict settings enabled in PHP. (Error: Strict standards: Creating default object from empty value)

Question: How can I modify my class to automatically create non-existing levels for me?

The code:

$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);
    }
}

解决方案

Taking a more oop view of your issue, you can create a class that models the concept of an multi-dimensional object.

The solution im posting doesn't extends from ArrayObject to archieve the goals you mention. As you tagged your question as oop, i think it´s important to reinforce the separation the way you store an object's state from how do you access it.

Hope this will help you archieve what you need!

From what you said, an multi-dimensional object is one that:

  • handles multiple levels of nested information
  • it does so by providing reading/writing access to the information via properties
  • behaves nicely when undefined properties are accessed. This means that, for example, you do the following on an empty instance: $config->database->host = 'localhost' the database and host levels are initialized automatically, and host will return 'localhost' when queried.
  • ideally, would be initialized from an associative arrays (because you can already parse config files into them)

Proposed Solution

So, how can those features be implemented?

The second one is easy: using PHP's __get and __set methods. Those will get called whenever an read/write is beign done on an inaccesible property (one that's not defined in an object). The trick will be then not to declare any property and handle propertie's operations through those methods and map the property name beign accesed as a key to an assosiative array used as storage. They'll provide basically an interface for accesing information stored internally.

For the third one, we need a way to create a new nesting level when a undeclared property is readed. The key point here is realizing that the returned value for the property must be an multi-dimensional object so further levels of nesting can be created from it also: whenever we´re asked for a property whose name is not present in the internal array, we´ll associate that name with a new instance of MultiDimensionalObject and return it. The returned object will be able to handle defined or undefined properties too.

When an undeclared property is written, all we have to do is assign it's name with the value provided in the internal array.

The fourth one is easy (see it on __construct implementation). We just have to make sure that we create an MultiDimensionalObject when a property's value is an array.

Finally, the fist one: the way we handle the second and third features allows us to read and write properties (declared and undeclared) in any level of nesting. You can do things like $config->foo->bar->baz = 'hello' on an empty instance and then query for $config->foo->bar->baz successfully.

Important Notice that MultiDimensionalObject instead of beign itself an array is it composed with an array, letting you change the way you store the object's state as needed.

Implementation

/* 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);
    }
}

Demo

Code: var_dump(new MultiDimensionalObject());

Result:

object(MultiDimensionalObject)[1]
    private 'properties' => 
        array
            empty

Code:

$data = array( 'database' => array ( 'host' => 'localhost' ) );
$config = new MultiDimensionalObject($data);        
var_dump($config->database);

Result:

object(MultiDimensionalObject)[2]
    private 'properties' => 
        array
            'host' => string 'localhost' (length=9)

Code:

$config->database->credentials->username = "admin";
$config->database->credentials->password = "pass";
var_dump($config->database->credentials);

Result:

object(MultiDimensionalObject)[3]
    private 'properties' => 
        array
          'username' => string 'admin' (length=5)
          'password' => string 'pass' (length=4)

Code:

$config->database->credentials->username;

Result:

admin

这篇关于在PHP扩展ArrayObject的正确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆