Элемент массива доступа, индексированный с помощью числовой строки

Я столкнулся с чем-то странным.

У меня есть php-массив, индексированный цифровыми ключами. Однако невозможно получить доступ к любому из элементов, потому что php автоматически обрабатывает числовые строки как целые числа, вызывая уведомление о недопустимом смещении.

В нормальных условиях его невозможно создать php-массив с числовыми индексами строк, но это может произойти с типом casting.

Воспроизведение:

$object = new stdClass();
$object->{'1'} = 'one';

$array = (array) $object;

var_dump($array);
/* produces
array(1) {
  ["1"]=>
  string(3) "one"
}
*/

//none of the following will work
$key = '1';
echo $array[1], $array['1'], $array["1"], $array[(string)1], $array[$key];

Это просто ошибка в кромке? Я столкнулся с проблемой при попытке улучшить свой ответ для другого вопроса SO

Пример живого кода: http://codepad.viper-7.com/dFSlH1

Ответы

Ответ 1

Невероятно, но это нормальное поведение в php, оно считалось ошибкой (ссылка) в 2008 году.

Но они просто указали на manual для трансляции с (array):

Если объект преобразуется в массив, результатом является массив, Элементы - это свойства объекта. Ключами являются переменная-член имена с несколькими заметными исключениями: целочисленные свойства недоступна;

Вместо этого вы можете использовать get_object_vars():

$object = new stdClass();
$object->{'1'} = 'one';

$array = get_object_vars( $object );

$key = '1';
echo $array[1]."<br>";
echo $array['1']."<br>";
echo $array["1"]."<br>";
echo $array[(string)1]."<br>";
echo $array[$key]."<br>";

Не объясняет, почему это происходит, но является решением, чтобы избежать проблемы с литой.

Отключить тему, но я подумал, может быть, это интересно. Нашел это в manual.

Чтобы избежать таких проблем, всегда используйте целое число ИЛИ строку в качестве индекса, не смешивайте его и не используйте целые числа в строке.

Пример смешанного массива:

$array = array(
    1    => "a",
    "1"  => "b",//overrides 1
    1.5  => "c",//overrides "1"
    true => "d",//overrides 1.5
);

var_dump($array);

Ответ 2

Вы можете использовать

$vars  = get_object_vars($object);
echo $vars[1];

Ответ 3

Строковые ключи, содержащие допустимые целочисленные значения, будут автоматически сбрасываться в целые ключи в "нормальном" создании массива, но кажется, что отбрасывание из объекта в массив не применяется к той же логике.

Однако можно исправить, используя

$array = array_combine(array_keys($array), array_values($array));

после строки, которая создает массив из объекта. http://codepad.viper-7.com/v5rGJa


Хотя, как сказал Дэйв в своем комментарии, использование get_object_vars выглядит как "более чистое" решение для меня.

Ответ 4

foreach ($array as $key => $value){
    var_dump($key);
    var_dump($value);
}

показывает

string(1) "1"
string(3) "one"

Но echo $array['"1"']; дает

E_NOTICE :  type 8 -- Undefined index: "1" -- at line 8

Это странно!