Как получить доступ к свойствам объекта с именами, такими как целые числа?

Как получить доступ к элементу массива PHP Associative, выход которого:

[highlighting] => stdClass Object ( [448364] => stdClass Object ( [Data] => Array ( [0] => Tax amount liability is ....... 

Я хочу получить доступ к строковому значению в ключе [0]. Я хочу сделать что-то вроде:

 print myVar->highlighting->448364->Data->0 

Но две цифры / целые числа, похоже, являются проблемой.

РЕДАКТИРОВАТЬ:

Я расскажу немного истории здесь, откуда я могу получить myVar. Я использую json_decode() что-то вроде:

 $myVar = json_decode(url) 

Обновлено для PHP 7.2

В PHP 7.2 было внесено изменение поведения для преобразования числовых клавиш в потоки объектов и массивов , что устраняет эту конкретную несогласованность и приводит к тому, что все следующие примеры ведут себя так, как ожидалось.

Еще одна вещь, которую нужно смутить!


Оригинальный ответ (относится к версиям выше 7.2.0)

PHP имеет свою долю темных переулков, которые вы действительно не хотите найти внутри. Свойства объекта с именами, которые являются числами, являются одним из них …

То, что они никогда не говорили вам

Факт №1: вы не можете получить доступ к свойствам с именами, имена которых не являются именами легальных переменных.

 $a = array('123' => '123', '123foo' => '123foo'); $o = (object)$a; echo $o->123foo; // error 

Факт № 2: вы можете получить доступ к таким свойствам с синтаксисом фигурных фигурных скобок

 $a = array('123' => '123', '123foo' => '123foo'); $o = (object)$a; echo $o->{'123foo'}; // OK! 

Факт №3: Но не если имя свойства – это все цифры!

 $a = array('123' => '123', '123foo' => '123foo'); $o = (object)$a; echo $o->{'123foo'}; // OK! echo $o->{'123'}; // error! 

Живой пример .

Факт № 4: Ну, если объект не пришел из массива в первую очередь.

 $a = array('123' => '123'); $o1 = (object)$a; $o2 = new stdClass; $o2->{'123'} = '123'; // setting property is OK echo $o1->{'123'}; // error! echo $o2->{'123'}; // works... WTF? 

Живой пример .

Довольно интуитивно, не согласны?

Что ты можешь сделать

Вариант №1: сделайте это вручную

Самый практичный подход – просто вернуть объект, который вас интересует, назад в массив, который позволит вам получить доступ к свойствам:

 $a = array('123' => '123', '123foo' => '123foo'); $o = (object)$a; $a = (array)$o; echo $o->{'123'}; // error! echo $a['123']; // OK! 

К сожалению, это не работает рекурсивно. Поэтому в вашем случае вам нужно сделать что-то вроде:

 $highlighting = (array)$myVar->highlighting; $data = (array)$highlighting['448364']->Data; $value = $data['0']; // at last! 

Вариант № 2: ядерный вариант

Альтернативным подходом было бы написать функцию, которая рекурсивно преобразует объекты в массивы:

 function recursive_cast_to_array($o) { $a = (array)$o; foreach ($a as &$value) { if (is_object($value)) { $value = recursive_cast_to_array($value); } } return $a; } $arr = recursive_cast_to_array($myVar); $value = $arr['highlighting']['448364']['Data']['0']; 

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

Вариант № 3: умение играть

Альтернативой предыдущей опции является использование встроенных функций JSON:

 $arr = json_decode(json_encode($myVar), true); $value = $arr['highlighting']['448364']['Data']['0']; 

Функции JSON помогают выполнять рекурсивное преобразование в массив без необходимости определять какие-либо внешние функции. Как бы это ни было желательно, у него есть недостаток «nuke» варианта № 2 и, кроме того, недостаток, заключающийся в том, что если в вашем объекте есть какие-либо строки, эти строки должны быть закодированы в UTF-8 (это требование json_encode ).

Просто хотел добавить к красноречивому объяснению Джона причину, почему это не удается. Все дело в том, что при создании массива php преобразует ключи в целые числа – если это возможно – что вызывает проблемы поиска на массивах, которые были переданы объектам, просто потому, что цифровой ключ сохраняется. Это проблематично, потому что все параметры доступа к ресурсам ожидают или конвертируют в строки. Вы можете подтвердить это, выполнив следующие действия:

 $arr = array('123' => 'abc'); $obj = (object) $arr; $obj->{'123'} = 'abc'; print_r( $obj ); 

Что будет выводить:

 stdClass Object ( [123] => 'abc', [123] => 'abc' ) 

Таким образом, у объекта есть два ключа свойств: одно числовое (к которому нельзя получить доступ) и одна строка. Это причина, по которой работает #Fact 4 Jon, потому что, устанавливая свойство с помощью фигурных скобок, вы всегда определяете строковый ключ, а не числовой.

Принимая решение Джона, но поворачивая его на голову, вы можете сгенерировать объект из вашего массива, который всегда имеет строковые ключи, делая следующее:

 $obj = json_decode(json_encode($arr)); 

С этого момента вы можете использовать любое из следующих способов: доступ таким образом всегда преобразует значение внутри фигурной скобки в строку:

 $obj->{123}; $obj->{'123'}; 

Хороший старый нелогичный PHP …

Я скопировал эту функцию из сети. Если он работает так, как он говорит («Функция преобразования объектов StdClass в многомерные массивы»), попробуйте выполнить следующее:

 <?php function objectToArray($d) { if (is_object($d)) { // Gets the properties of the given object // with get_object_vars function $d = get_object_vars($d); } if (is_array($d)) { /* * Return array converted to object * Using __FUNCTION__ (Magic constant) * for recursive call */ return array_map(__FUNCTION__, $d); } else { // Return array return $d; } } ?> 
  • сначала передайте свой массив функции objectToArray
  • затем возьмите возвращаемое значение
  • echo [highlighting][448364][Data][0]

Источник: PHP stdClass для массива и массива в stdClass

Последняя альтернатива полному ответу Джона:

Просто используйте json_decode (), а второй параметр – true .

 $array = json_decode($url, true); 

Затем он возвращает ассоциативный массив, а не объект, поэтому нет необходимости преобразовывать его после факта.

Это может быть не подходит для каждого приложения, но это действительно помогло мне легко ссылаться на свойство oroginal объекта.

Решение было найдено в этом учебнике – http://nitschinger.at/Handling-JSON-like-a-boss-in-PHP/

С уважением

Боюсь, вам не разрешено называть объекты, начинающиеся с численных значений. Переименуйте первый «448364», начиная с буквы.

Второй – это массив, к которому должны быть доступны скобки:

 print myVar->highlighting->test_448364->Data[0] 

вместо

Если объект начинается с @ like:

 SimpleXMLElement Object ( [@attributes] => Array ( [href] => qwertyuiop.html [id] => html21 [media-type] => application/xhtml+xml ) ) 

Вы должны использовать:

 print_r($parent_object->attributes()); 

потому что $parent_object->{'@attributes'} или $parent_object['@attributes'] не будет работать.