У меня есть массив и PHP, и когда я его распечатываю, я вижу значения, которые мне нужны для доступа, но когда я пытаюсь получить их по их ключу, я получаю уведомление PHP. Я напечатал массив с помощью print_r :
Array ( [207] => sdf [210] => sdf )
Когда я пытаюсь получить доступ к массиву с помощью индекса, я получаю неопределенное уведомление о смещении. Вот мой код:
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)
См. Этот раздел о преобразовании объекта в массив в руководстве 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 для необязательного аргумента-аргумента, чтобы указать, что вы хотите, чтобы массив не был объектом:
$output = json_decode('{"207":"sdf","210":"sdf"}', true); print_r($output); echo $output[207]; echo $output["207"];
Проблема возникает при приведении в 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"}]'
Эта структура данных имеет несколько преимуществ по сравнению с существующей:
Если требуется свойство map → object map, оно может быть быстро получено, например:
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 гораздо более чистого решения, хотя, хотя я понимаю, что это может быть невозможно.
Я только что нашел эту ошибку, которая заставляет элементы массива быть недоступными иногда в PHP, когда массив создается вызовом unserialize .
Создайте тестовый PHP-файл, содержащий (или запустите из командной строки) следующий скрипт:
<?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
Пытаться
var_dump($output); foreach ($output as $key => val) { var_dump($key); var_dump($val); }
чтобы узнать больше о том, что происходит.
Какая точная строка / заявление бросает вам предупреждение?
Как вы напечатали массив? Я бы предложил print_r($arrayName);
Затем вы можете печатать отдельные элементы, такие как: echo $arrayName[0];
Попробуйте использовать мой подход:
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);
Просто поставьте error_reporting (0); в вашем методе или при запуске файла. Это решит вашу проблему.