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


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

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

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

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

но две цифры / целые числа там, кажется, проблема.

EDIT:

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

$myVar = json_decode(url)
6 78

6 ответов:

обновлено для 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 услужливо выполняют рекурсивное преобразование в массив без необходимости определять какие-либо внешние функции. Однако желательно это похоже, у него есть" ядерный " недостаток варианта №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 работает, потому что, устанавливая свойство с помощью фигурных скобок, вы всегда определяете строковый ключ, а не числовой.

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

$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 функции
  • затем принять возвращаемое значение
  • Эхо [highlighting][448364][Data][0]

источник: PHP stdClass to Array и Array to stdClass

последняя альтернатива исчерпывающему ответу Джона:

просто использовать json_decode() со вторым параметром, равным правда.

$array = json_decode($url, true);

Это возвращает ассоциативный массив, а не объект, поэтому не нужно конвертировать постфактум.

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

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

в отношении

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

второй-это массив, к которому нужно обращаться с помощью скобок:

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

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

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'] не работает.