Чтобы понять, почему я спрашиваю об этом, прочитайте это и комментарии к нему. Рассмотрим следующий код:
$obj = new stdClass; $obj->{10} = 'Thing'; $objArray = (array) $obj; var_dump($objArray);
Производит:
array(1) { ["10"]=> string(5) "Thing" }
Теперь я не могу получить доступ к этому через $objArray['10']
потому что PHP преобразует числовые строки в целые ключи. В руководстве явно указывается, что «целочисленные свойства недоступны» при бросании массива в объект. Или они?
Чтобы доказать неправильные документы, я создал класс:
class strKey implements ArrayAccess { private $arr; public function __construct(&$array) { $this->arr = &$array; } public function offsetExists($offset) { foreach ($this->arr as $key => $value) { if ($key == $offset) { return true; } } return false; } public function offsetGet($offset) { foreach ($this->arr as $key => $value) { if ($key == $offset) { return $value; } } return null; } public function offsetSet($offset, $value) { foreach($this->arr as $key => &$thevalue) { if ($key == $offset) { $thevalue = $value; return; } } // if $offset is *not* present... if ($offset === null) { $this->arr[] = $value; } else { // this won't work with string keys $this->arr[$offset] = $value; } } // can't implement this public function offsetUnset($offset) { foreach ($this->arr as $key => &$value) { if ($key == $offset) { //$value = null; } } } }
Теперь я могу сделать (demo) :
$b = new strKey($objArray); echo $b['10']; // Thing $b['10'] = 'Something else'; // because the classes works with a reference to the original array, // this will give us a modified array: var_dump($objArray);
Последний фрагмент головоломки: как мне удалить элемент, чей ключ является числовой строкой? Я попытался использовать ArrayIterator
, key()
, next()
и т. Д., Но это не сработает. Я не могу найти способ устранить это.
Любое решение должно работать с исходным массивом, а не создавать копию и заменять оригинал.
Вы можете попытаться удалить его с помощью array_splice()
, если знаете его смещение ( foreach (...) { $offset++; ... }
), но хранение данных в таких массивах, как это, действительно не очень хорошая идея. Вы должны преобразовать эти объекты в массив с foreach:
foreach ( $obj as $key => $value ) $array[$key] = $value;
Следуя совету pozs, вот результат offsetUnset()
. Я также добавил новый offsetSet()
который поддерживает добавление цифровых клавиш.
public function offsetUnset($offset) { $off = 0; foreach ($this->arr as $key => $value) { if ($key === $offset) { array_splice($this->arr, $off, 1); return; } $off++; } } public function offsetSet($offset, $value) { foreach($this->arr as $key => &$thevalue) { if ($key === $offset) { $thevalue = $value; return; } } // if $offset is *not* present... if ($offset === null) { $this->arr[] = $value; } // it's a numeric string key, now we have to hack it else if (strval(intval($offset)) === $offset) { // create new array via loophole: $tempObj = new stdClass; $tempObj->{$offset} = $value; // append to old array (+= doesn't create copies) $this->arr += (array) $tempObj; unset($tempObj); } // we are dealing with a normal key else { $this->arr[$offset] = $value; } }
сpublic function offsetUnset($offset) { $off = 0; foreach ($this->arr as $key => $value) { if ($key === $offset) { array_splice($this->arr, $off, 1); return; } $off++; } } public function offsetSet($offset, $value) { foreach($this->arr as $key => &$thevalue) { if ($key === $offset) { $thevalue = $value; return; } } // if $offset is *not* present... if ($offset === null) { $this->arr[] = $value; } // it's a numeric string key, now we have to hack it else if (strval(intval($offset)) === $offset) { // create new array via loophole: $tempObj = new stdClass; $tempObj->{$offset} = $value; // append to old array (+= doesn't create copies) $this->arr += (array) $tempObj; unset($tempObj); } // we are dealing with a normal key else { $this->arr[$offset] = $value; } }
Я официально победил PHP. Ура!