PHP ArrayAccess 设置多维
PHP ArrayAccess set multidimensional
编辑: 我意识到文字的数量可能令人生畏。本题实质:
如何以可以设置多维值的方式实现 ArrayAccess?
我知道已经讨论过 here 但我似乎无法正确实现 ArrayAccess 接口。
基本上,我有一个 class 来处理带有数组的应用程序配置并实现了 ArrayAccess
。检索值工作正常,甚至是来自嵌套键 ($port = $config['app']['port'];
) 的值。但是,设置值仅适用于一维数组:一旦我尝试(取消)设置一个值(例如上一个示例中的端口),我就会收到以下错误消息:
Notice: Indirect modification of overloaded element <object name> has no effect in <file> on <line>
现在普遍的看法似乎是 offsetGet()
方法必须 return by reference (&offsetGet()
)。然而,这并没有解决问题,恐怕我不知道如何正确地实现该方法 - 为什么要使用 getter 方法来设置一个值? php 文档 here 也不是很有帮助。
要直接复制此 (PHP 5.4-5.6),请在下面找到示例代码:
<?php
class Config implements \ArrayAccess
{
private $data = array();
public function __construct($data)
{
$this->data = $data;
}
/**
* ArrayAccess Interface
*
*/
public function offsetSet($offset, $value)
{
if (is_null($offset)) {
$this->data[] = $value;
} else {
$this->data[$offset] = $value;
}
}
public function &offsetGet($offset)
{
return isset($this->data[$offset]) ? $this->data[$offset] : null;
}
public function offsetExists($offset)
{
return isset($this->data[$offset]);
}
public function offsetUnset($offset)
{
unset($this->data[$offset]);
}
}
$conf = new Config(array('a' => 'foo', 'b' => 'bar', 'c' => array('sub' => 'baz')));
$conf['c']['sub'] = 'notbaz';
编辑 2: 正如 Ryan 指出的那样,解决方案是改用 ArrayObject(它已经实现了 ArrayAccess
、Countable
和 IteratorAggregate
).
要将其应用于包含数组的 class,请像这样构造它:
<?php
class Config extends \ArrayObject
{
private $data = array();
public function __construct($data)
{
$this->data = $data;
parent::__construct($this->data);
}
/**
* Iterator Interface
*
*/
public function getIterator() {
return new \ArrayIterator($this->data);
}
/**
* Count Interface
*
*/
public function count()
{
return count($this->data);
}
}
我将其用于我的配置库 libconfig
,该库可在 Github 上根据 MIT 许可证获得。
我不确定这是否有用。我注意到 ArrayObject
class 是 'interesting'...
我不确定这是不是 'answer'。更多的是关于这个的观察 class.
它按照标准正确处理了 'multidimensional array' 内容。
您也许可以添加方法,让它做更多您想做的事情?
<?php //
class Config extends \ArrayObject
{
// private $data = array();
public function __construct(array $data = array())
{
parent::__construct($data);
}
}
$conf = new Config(array('a' => 'foo', 'b' => 'bar', 'c' => array('sub' => 'baz')));
$conf['c']['sub'] = 'notbaz';
$conf['c']['sub2'] = 'notbaz2';
var_dump($conf, $conf['c'], $conf['c']['sub']);
unset($conf['c']['sub']);
var_dump('isset?: ', isset($conf['c']['sub']));
var_dump($conf, $conf['c'], $conf['c']['sub2']);
输出:
object(Config)[1]
public 'a' => string 'foo' (length=3)
public 'b' => string 'bar' (length=3)
public 'c' =>
array
'sub' => string 'notbaz' (length=6)
'sub2' => string 'notbaz2' (length=7)
array
'sub' => string 'notbaz' (length=6)
'sub2' => string 'notbaz2' (length=7)
string 'notbaz' (length=6)
string 'isset?: ' (length=8)
boolean false
object(Config)[1]
public 'a' => string 'foo' (length=3)
public 'b' => string 'bar' (length=3)
public 'c' =>
array
'sub2' => string 'notbaz2' (length=7)
array
'sub2' => string 'notbaz2' (length=7)
string 'notbaz2' (length=7)
编辑: 我意识到文字的数量可能令人生畏。本题实质:
如何以可以设置多维值的方式实现 ArrayAccess?
我知道已经讨论过 here 但我似乎无法正确实现 ArrayAccess 接口。
基本上,我有一个 class 来处理带有数组的应用程序配置并实现了 ArrayAccess
。检索值工作正常,甚至是来自嵌套键 ($port = $config['app']['port'];
) 的值。但是,设置值仅适用于一维数组:一旦我尝试(取消)设置一个值(例如上一个示例中的端口),我就会收到以下错误消息:
Notice: Indirect modification of overloaded element <object name> has no effect in <file> on <line>
现在普遍的看法似乎是 offsetGet()
方法必须 return by reference (&offsetGet()
)。然而,这并没有解决问题,恐怕我不知道如何正确地实现该方法 - 为什么要使用 getter 方法来设置一个值? php 文档 here 也不是很有帮助。
要直接复制此 (PHP 5.4-5.6),请在下面找到示例代码:
<?php
class Config implements \ArrayAccess
{
private $data = array();
public function __construct($data)
{
$this->data = $data;
}
/**
* ArrayAccess Interface
*
*/
public function offsetSet($offset, $value)
{
if (is_null($offset)) {
$this->data[] = $value;
} else {
$this->data[$offset] = $value;
}
}
public function &offsetGet($offset)
{
return isset($this->data[$offset]) ? $this->data[$offset] : null;
}
public function offsetExists($offset)
{
return isset($this->data[$offset]);
}
public function offsetUnset($offset)
{
unset($this->data[$offset]);
}
}
$conf = new Config(array('a' => 'foo', 'b' => 'bar', 'c' => array('sub' => 'baz')));
$conf['c']['sub'] = 'notbaz';
编辑 2: 正如 Ryan 指出的那样,解决方案是改用 ArrayObject(它已经实现了 ArrayAccess
、Countable
和 IteratorAggregate
).
要将其应用于包含数组的 class,请像这样构造它:
<?php
class Config extends \ArrayObject
{
private $data = array();
public function __construct($data)
{
$this->data = $data;
parent::__construct($this->data);
}
/**
* Iterator Interface
*
*/
public function getIterator() {
return new \ArrayIterator($this->data);
}
/**
* Count Interface
*
*/
public function count()
{
return count($this->data);
}
}
我将其用于我的配置库 libconfig
,该库可在 Github 上根据 MIT 许可证获得。
我不确定这是否有用。我注意到 ArrayObject
class 是 'interesting'...
我不确定这是不是 'answer'。更多的是关于这个的观察 class.
它按照标准正确处理了 'multidimensional array' 内容。
您也许可以添加方法,让它做更多您想做的事情?
<?php //
class Config extends \ArrayObject
{
// private $data = array();
public function __construct(array $data = array())
{
parent::__construct($data);
}
}
$conf = new Config(array('a' => 'foo', 'b' => 'bar', 'c' => array('sub' => 'baz')));
$conf['c']['sub'] = 'notbaz';
$conf['c']['sub2'] = 'notbaz2';
var_dump($conf, $conf['c'], $conf['c']['sub']);
unset($conf['c']['sub']);
var_dump('isset?: ', isset($conf['c']['sub']));
var_dump($conf, $conf['c'], $conf['c']['sub2']);
输出:
object(Config)[1]
public 'a' => string 'foo' (length=3)
public 'b' => string 'bar' (length=3)
public 'c' =>
array
'sub' => string 'notbaz' (length=6)
'sub2' => string 'notbaz2' (length=7)
array
'sub' => string 'notbaz' (length=6)
'sub2' => string 'notbaz2' (length=7)
string 'notbaz' (length=6)
string 'isset?: ' (length=8)
boolean false
object(Config)[1]
public 'a' => string 'foo' (length=3)
public 'b' => string 'bar' (length=3)
public 'c' =>
array
'sub2' => string 'notbaz2' (length=7)
array
'sub2' => string 'notbaz2' (length=7)
string 'notbaz2' (length=7)