PHP массив со значением по умолчанию для несуществующих индексов - PullRequest
9 голосов
/ 22 сентября 2009

Мне нравится реализация 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. Тем не менее, любое значение массива равно нулю. Есть идеи для альтернативных реализаций?

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

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

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

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

Ответы [ 4 ]

6 голосов
/ 22 сентября 2009
$da->setDefault(1);

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

class DefaultArray extends ArrayObject
{
    public function __construct($value = null){
        if(is_null($value))
        {
            $this->value = 'default';
        } else {
            $this->value = $value;
        }
    }
}
3 голосов
/ 22 сентября 2009

Попробуйте магические методы __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);
0 голосов
/ 09 июля 2015

Вы можете использовать мою крошечную библиотеку 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)

Проверьте документы для большего количества примеров

0 голосов
/ 22 сентября 2009

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

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

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

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

Но я вижу, у тебя намного опрятнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...