Undefined смещение при доступе к элементу массива, который существует
У меня есть массив и PHP, и когда я его распечатываю, я вижу значения, которые мне нужны для доступа, но когда я пытаюсь получить доступ к ним по их ключу, я получаю уведомление PHP. Я напечатал массив print_r:
Array
(
[207] => sdf
[210] => sdf
)
Когда я пытаюсь получить доступ к массиву с помощью индекса, я получаю уведомление о смещении undefined. Вот мой код:
print_r($output);
echo $output[207]; // Undefined Offset
echo $output["207"]; // Undefined Offset
Массив $output
является результатом вызова array_diff_key и первоначально вводится как JSON через HTTP-запрос POST.
array_keys дает мне следующее:
Array
(
[0] => 207
[1] => 210
)
В ответ на комментарии:
var_dump(key($output));
выходы:
string(3) "207"
var_dump(isset($output[key($output)]));
выходы:
bool(false)
Ответы
Ответ 1
См. этот раздел о преобразовании объекта в массив в Руководство по PHP:
Ключи - это имена переменных-членов с несколькими заметными исключениями: целочисленные свойства недоступны; частные переменные имеют имя класса, добавленное к имени переменной; защищенные переменные имеют "*", добавленные к имени переменной.
При преобразовании в массив из объекта в PHP целые массивные ключи хранятся внутри как строки. Когда вы обращаетесь к элементам массива в PHP или обычно используете массив, ключи, содержащие действительные целые числа, будут автоматически преобразованы в целые числа. Целое число, сохраненное внутри строки в виде строки, является недоступным ключом.
Обратите внимание на разницу:
$x = (array)json_decode('{"207":"test"}');
var_dump(key($x)); // string(3) "207"
var_dump($x);
// array(1) {
// ["207"]=>
// string(4) "test"
// }
$y['207'] = 'test';
var_dump(key($y)); // int(207)
var_dump($y);
// array(1) {
// [207]=>
// string(4) "test"
// }
print_r на обоих этих массивах дает идентичный результат, но с var_dump вы можете видеть различия.
Вот какой код, который воспроизводит вашу точную проблему:
$output = (array)json_decode('{"207":"sdf","210":"sdf"}');
print_r($output);
echo $output[207];
echo $output["207"];
И простое исправление состоит в том, чтобы передать true
в json_decode для необязательного аргумента assoc
, чтобы указать, что вы хотите массив не объект:
$output = json_decode('{"207":"sdf","210":"sdf"}', true);
print_r($output);
echo $output[207];
echo $output["207"];
Ответ 2
Проблема возникает, когда casting в array
объект, который имеет строковые ключи, которые являются целыми числами.
Если у вас есть этот объект:
object(stdClass)#1 (2) {
["207"]=>
string(3) "sdf"
["210"]=>
string(3) "sdf"
}
и вы добавили его с помощью
$array = (array)$object
вы получаете этот массив
array(2) {
["207"]=>
string(3) "sdf"
["210"]=>
string(3) "sdf"
}
у которого есть ключи, к которым можно получить доступ только путем их циклического перехода, поскольку прямой доступ, такой как $array["207"]
, всегда будет преобразован в $array[207]
, который не существует.
Так как вы получаете объект, подобный тому, который указан выше от json_decode()
, применяемый к строке типа
$json = '{"207":"sdf", "210":"sdf"}'
Лучшим решением было бы избежать ввода числовых клавиш в первую очередь. Вероятно, они лучше всего моделируются как числовые свойства массива объектов:
$json = '[{"numAttr":207, "strAttr":"sdf"}, {"numAttr":210, "strAttr":"sdf"}]'
Эта структура данных имеет несколько преимуществ по сравнению с настоящим:
- он лучше отражает исходные данные, как набор объектов
которые имеют числовое свойство
- он легко расширяется с другими свойствами
- он более портативен в разных системах
(как вы видите, ваша текущая структура данных вызывает проблемы на PHP, но если вы
должно случиться, что вы используете другой язык, с которым вы можете легко столкнуться
аналогичные проблемы).
Если свойство → необходима карта объектов, ее можно быстро получить, например, следующим образом:
function getNumAttr($obj) { return $obj->numAttr; } // for backward compatibility
$arr = json_decode($json); // where $json = '[{"numAttr":...
$map = array_combine(array_map('getNumAttr', $arr), $arr);
Другим решением было бы сделать так, как предложил ascii-lime: force json_decode()
для вывода ассоциативных массивов вместо объектов, установив его второй параметр true
:
$map = json_decode($json, true);
Для ваших входных данных это производит напрямую
array(2) {
[207]=>
string(3) "sdf"
[210]=>
string(3) "sdf"
}
Обратите внимание, что ключи массива теперь являются целыми числами вместо строк.
Я бы рассмотрел возможность изменения структуры данных JSON гораздо более чистого решения, хотя, хотя я понимаю, что это может быть невозможно.
Ответ 3
Я только что нашел эту ошибку, которая заставляет элементы массива быть недоступными иногда в PHP, когда массив создается вызовом unserialize.
Создайте тестовый PHP файл, содержащий (или запустите из командной строки) следующий script:
<?php
$a = unserialize('a:2:{s:2:"10";i:1;s:2:"01";i:2;}');
print $a['10']."\n";
$a['10'] = 3;
$a['01'] = 4;
print_r($a);
foreach ($a as $k => $v)
{
print 'KEY: ';
var_dump($k);
print 'VAL: ';
var_dump($v);
print "\n";
}
Если вы получаете ошибки, у вас есть версия PHP с этой ошибкой, и я рекомендую перейти на PHP 5.3
Ответ 4
Попробуйте
var_dump($output);
foreach ($output as $key => val) {
var_dump($key);
var_dump($val);
}
чтобы узнать больше о том, что происходит.
Какая точная строка/оператор бросает вам предупреждение?
Ответ 5
Как вы напечатали массив? Я бы предложил print_r($arrayName);
Далее вы можете печатать отдельные элементы, например: echo $arrayName[0];
Ответ 6
Попробуйте использовать мой подход:
class ObjectToArray {
public static function convert( $object ) {
if( !is_object( $object ) && !is_array( $object ) ) {
return $object;
}
if( is_object( $object ) ) {
$object = get_object_vars( $object );
}
return array_map( 'ObjectToArray::convert', $object );
}
}
$aNewArray = ObjectToArray::convert($oYourObject);
Ответ 7
Просто поставьте error_reporting (0); в вашем методе или при запуске файла. Это решит вашу проблему.