Массив PHP со значением по умолчанию для несуществующих индексов

Мне нравится реализация Hash Ruby, где вы можете инициализировать объект Hash со значением по умолчанию. На данный момент я борюсь с реализацией аналогичного объекта в PHP. Это мой первый (нерабочий) выстрел по этому поводу.

class DefaultArray extends ArrayObject { protected $_defaultValue; public function setDefault($defaultValue) { $this->_defaultValue = $defaultValue; } public function offsetExists($index) { return true; } public function offsetGet($index) { if(!parent::offsetExists($index)) { if(is_object($this->_defaultValue)) $default = clone $this->_defaultValue; else $default = $this->_defaultValue; parent::offsetSet($index, $default); } return parent::offsetGet($index); } } $da = new DefaultArray(); assert($da["dummy"] == null); $da->setDefault = 1; assert($da["dummy2"] == 1); 

Второе утверждение не удастся. Выполнение кода показывает, что вызывается функция offsetGet, и выполняется условие if. Тем не менее любое значение массива равно null. Любые идеи для альтернативных реализаций?

Я устал писать

 if(!isset($myarr['value'])) $myarr['value'] = new MyObj(); $myarr['value']->myVal=5; 

вместо того, чтобы просто писать

 $myarr['value']->myVal=5; 

 $da->setDefault(1); 

Вы также можете использовать магическую функцию __construct:

 class DefaultArray extends ArrayObject { public function __construct($value = null){ if(is_null($value)) { $this->value = 'default'; } else { $this->value = $value; } } } 

Попробуйте магические методы __get .

 class DefaultArray extends ArrayObject { protected $_defaultValue; public function setDefault($defaultValue) { $this->_defaultValue = $defaultValue; } public function __get($index) { return $this->offsetGet($index); } public function offsetGet($index) { if(!parent::offsetExists($index)) { if (is_object($this->_defaultValue)) { $default = clone $this->_defaultValue; } else { $default = $this->_defaultValue; } parent::offsetSet($index, $default); } return parent::offsetGet($index); } } 

Теперь вам просто нужно использовать разные ключи, поскольку доступ на чтение инициализирует элементы массива:

 $da = new DefaultArray(); assert($da['foo'] == null); $da->setDefault(1); assert($da['bar'] == 1); 

Вы можете использовать мою крошечную библиотеку ValueResolver в этом случае, например:

 class DefaultArray extends ArrayObject { public function __construct($value = null){ $this->value = ValueResolver::resolve($value, 'default'); // returns 'default' if $value is null } } 

и не забывайте использовать использование пространства имен use LapaLabs\ValueResolver\Resolver\ValueResolver;

Также есть возможность приведения типов, например, если значение переменной должно быть integer , поэтому используйте это:

 $id = ValueResolver::toInteger('6 apples', 1); // returns 6 $id = ValueResolver::toInteger('There are no apples', 1); // returns 1 (used default value) 

Проверьте документы для получения дополнительных примеров.

Почему так сложно?

 function initVal($value) { global $myarr; if(!isset($myarr['value'])) $myarr['value'] = new MyObj(); } 

Теперь вам просто нужно позвонить:

 initVal('bla'); $myarr['bla']->bla = 'bla'; 

Но я вижу, что ваш гораздо более аккуратный.