Подтвердить что ты не робот

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)
4b9b3361

Ответ 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); в вашем методе или при запуске файла. Это решит вашу проблему.