103 votes

Comment accéder aux propriétés d'un objet dont les noms sont des entiers ou des noms de propriétés invalides ?

J'utilise json_decode() quelque chose comme :

$myVar = json_decode($data)

Ce qui me donne un résultat comme celui-ci :

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

Je veux accéder à la valeur de la chaîne dans la clé [0]. Lorsque j'essaie de faire quelque chose comme :

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

Je reçois cette erreur :

Erreur d'analyse : erreur de syntaxe, T_DNUMBER inattendu

Il semble y avoir un problème avec les deux chiffres/nombres entiers.

310voto

Jon Points 194296

Mise à jour pour PHP 7.2

PHP 7.2 a introduit un changement comportemental pour conversion des clés numériques dans les casts d'objets et de tableaux qui corrige cette incohérence particulière et fait en sorte que tous les exemples suivants se comportent comme prévu.

Une chose de moins pour laquelle il faut s'embrouiller !


Réponse originale (s'applique aux versions antérieures à 7.2.0)

Le PHP a sa part de ruelles sombres que vous vraiment ne veulent pas se retrouver à l'intérieur. Les propriétés des objets dont les noms sont des nombres en font partie...

Ce qu'ils ne vous ont jamais dit

Fait n° 1 : Vous ne pouvez pas accéder facilement aux propriétés dont le nom n'est pas un nom de variable légal.

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

Fait n°2 : Vous peut accéder à ces propriétés avec la syntaxe de l'accolade

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

Fait n°3 : Mais no si le nom de la propriété est composé de tous les chiffres !

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

Exemple concret .

Fait n°4 : A moins que l'objet ne provienne pas d'un tableau en premier lieu.

$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?

Exemple concret .

Plutôt intuitif, vous ne trouvez pas ?

Ce que vous pouvez faire

Option n° 1 : le faire manuellement

L'approche la plus pratique consiste simplement à retranscrire l'objet qui vous intéresse dans un tableau, ce qui vous permettra d'accéder aux propriétés :

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

Malheureusement, cela ne fonctionne pas de manière récursive. Donc, dans votre cas, vous devez faire quelque chose comme :

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

Option n° 2 : l'option nucléaire

Une autre approche consisterait à écrire une fonction qui convertit les objets en tableaux de manière récursive :

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'];

Cependant, je ne suis pas convaincu qu'il s'agisse d'une meilleure option dans tous les cas, car elle convertira inutilement en tableaux toutes les propriétés que vous êtes en train d'utiliser. no qui vous intéressent, ainsi que ceux qui vous intéressent.

Option n° 3 : jouer la carte de l'intelligence

Une alternative à l'option précédente consiste à utiliser les fonctions JSON intégrées :

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

Les fonctions JSON effectuent utilement une conversion récursive en tableau sans qu'il soit nécessaire de définir des fonctions externes. Aussi désirable que cela puisse paraître, cette option présente l'inconvénient de l'option n° 2. et en outre l'inconvénient que s'il y a des chaînes de caractères à l'intérieur de votre objet, ces chaînes de caractères doit doivent être encodés en UTF-8 (il s'agit d'une exigence de l'UE). json_encode ).

1 votes

Fait n°0 : Casting arrays into objects should not make no stinky sense in first place. Fait n°1 à Fait n°3 : inutile.

5 votes

@Pacerier : Je suis d'accord pour dire que c'est un peu discutable, mais ça peut totalement avoir du sens dans certaines situations. Quoi qu'il en soit, puisque c'est documenté dans le manuel pour travailler comme ça, nos opinions personnelles n'ont pas vraiment d'importance.

0 votes

Une alternative à l'option 3 qui ne nécessite pas UTF-8 serait la suivante $o = unserialize('O:8:"StdClass"' . substr(serialize($a),1));

11voto

pebbl Points 8909

Je voulais juste ajouter à l'explication éloquente de Jon la raison pour laquelle cela échoue. C'est parce que lors de la création d'un tableau, php convertit les clés en nombres entiers - s'il le peut - ce qui cause des problèmes de recherche sur les tableaux qui ont été convertis en objets, simplement parce que la clé numérique est préservée. Ceci est problématique car toutes les options d'accès aux propriétés s'attendent à ce qu'elles soient converties en chaînes de caractères. Vous pouvez le confirmer en faisant ce qui suit :

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

Ce qui donnerait :

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

L'objet a donc deux clés de propriété, l'une numérique (à laquelle on ne peut accéder) et l'autre basée sur une chaîne de caractères. C'est la raison pour laquelle Jon #Fact 4 fonctionne, car en définissant la propriété à l'aide d'accolades, vous définissez toujours une clé basée sur une chaîne de caractères, plutôt que sur un chiffre.

En prenant la solution de Jon, mais en la retournant, vous pouvez générer un objet à partir de votre tableau qui a toujours des clés basées sur des chaînes en faisant ce qui suit :

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

À partir de maintenant, vous pouvez utiliser l'une ou l'autre des méthodes suivantes, car l'accès de cette manière convertit toujours la valeur à l'intérieur de l'accolade en une chaîne de caractères :

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

Ce bon vieux PHP illogique...

3voto

umesh kadam Points 539

Pour PHP 7

Accès aux propriétés d'un objet ayant des nombres comme nom de propriété. Principalement nécessaire après avoir transformé un tableau en objet.

    $arr = [2,3,7];
    $o = (object) $arr;

    $t = "1";
    $t2 = 1;
    $t3 = (1);

    echo $o->{1};      // 3
    echo $o->{'1'};   // 3
    echo $o->$t;        // 3
    echo $o->$t2;       // 3
    echo $o->$t3;       // 3

    echo $o->1;       // error
    echo $o->(1);      // error

2voto

Zydnar Points 866

Si un objet commence par @ comme :

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

Vous devez utiliser :

print_r($parent_object->attributes());

parce que $parent_object->{'@attributes'} o $parent_object['@attributes'] ne fonctionnera pas.

0 votes

3 ans plus tard et cela aide toujours les gens, merci ! Bien que votre réponse corrige mon problème, il manque une explication. Quelqu'un est-il en mesure d'expliquer la raison de ce problème ?

2voto

Bluekable Points 41

Une dernière alternative à la réponse complète de Jon :

Il suffit d'utiliser la fonction json_decode() avec le deuxième paramètre réglé sur vrai .

$array = json_decode($url, true);

Cela renvoie alors un tableau associatif plutôt qu'un objet, il n'est donc pas nécessaire de le convertir après coup.

Cette méthode ne convient peut-être pas à toutes les applications, mais elle m'a vraiment aidé à référencer facilement une propriété de l'objet original.

La solution a été trouvée dans ce tutoriel - http://nitschinger.at/Handling-JSON-like-a-boss-in-PHP/

Salutations

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X