2015-04-05 3 views
1

EDIT: Я понял, что количество текста может быть пугающим. Суть этого вопроса:
Как реализовать ArrayAccess таким образом, чтобы можно было установить многомерные значения?PHP ArrayAccess set multimensional

 


 

Я знаю, что это обсуждалось уже here но мне кажется, не в состоянии правильно реализовать интерфейс 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 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'; 

 


 

EDIT 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.

ответ

3

Я не уверен, что это будет полезно. Я заметил, что класс 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) 
+0

Эй, спасибо большое! Мне пришлось реализовать функцию 'getIterator', но это было легко (обновил вопрос). Спасибо! :) –

Смежные вопросы