массивы — PHP ArrayAccess установить многомерный

РЕДАКТИРОВАТЬ: Я понял, что количество текста может быть пугающим. Суть этого вопроса:
Как реализовать ArrayAccess таким образом, чтобы сделать возможной настройку многомерных значений?

 


 

Я знаю, что это обсуждалось Вот уже, но я не могу правильно реализовать интерфейс ArrayAccess.

По сути, у меня есть класс для обработки конфигурации приложения с массивом и реализован ArrayAccess, Получение значений работает нормально, даже значения из вложенных ключей ($port = $config['app']['port'];). Настройка значений работает только для одномерных массивов, однако: как только я пытаюсь (не) установить значение (например, порт в предыдущем примере), я получаю следующее сообщение об ошибке:

Notice:  Indirect modification of overloaded element <object name> has no effect in <file> on <line>

Похоже, общее мнение таково, что offsetGet() метод должен возвращаться по ссылке (&offsetGet()). Это, однако, не решает проблему, и я боюсь, что не знаю, как правильно реализовать этот метод — почему метод getter используется для установки значения? Php doc Вот тоже не очень помогает.

Чтобы напрямую скопировать это (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: Решение, как указал Райан, состояло в том, чтобы вместо этого использовать ArrayObject (который уже реализует ArrayAccess, Countable а также IteratorAggregate).
Чтобы применить его к классу, содержащему массив, структурируйте его так:

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

 

Я использовал это для моей библиотеки Config libconfig который доступен на Github под лицензией MIT.

1

Решение

Я не уверен, будет ли это полезно. Я заметил, что ArrayObject класс «интересный» …

Я не уверен, что это даже «ответ». Это скорее наблюдение за этим классом.

Он корректно обрабатывает «многомерный массив» как стандарт.

Возможно, вы сможете добавить методы, чтобы сделать больше того, что вы хотите?

<?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)
3

Другие решения

Других решений пока нет …