Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access object properties with names like integers or invalid property names?

I am using json_decode() something like:

$myVar = json_decode($data)

Which gives me output like this:

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

I want to access the string value in the key [0]. When I try to do something like:

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

I get this error:

Parse error: syntax error, unexpected T_DNUMBER

The two numerals/integers there seems to be problem.

like image 507
avinash shah Avatar asked Apr 26 '12 12:04

avinash shah


People also ask

How do you access the properties of an object in PHP?

Within class methods non-static properties may be accessed by using -> (Object Operator): $this->property (where property is the name of the property). Static properties are accessed by using the :: (Double Colon): self::$property .

How do you access the properties of an object with a variable?

Answer: Use the Square Bracket ( [] ) Notation There are two ways to access or get the value of a property from an object — the dot ( . ) notation, like obj. foo , and the square bracket ( [] ) notation, like obj[foo] .

How do you access object properties in typescript?

To dynamically access an object's property: Use keyof typeof obj as the type of the dynamic key, e.g. type ObjectKey = keyof typeof obj; . Use bracket notation to access the object's property, e.g. obj[myVar] .


4 Answers

Updated for PHP 7.2

PHP 7.2 introduced a behavioral change to converting numeric keys in object and array casts, which fixes this particular inconsistency and makes all the following examples behave as expected.

One less thing to be confused about!


Original answer (applies to versions earlier than 7.2.0)

PHP has its share of dark alleys that you really don't want to find yourself inside. Object properties with names that are numbers is one of them...

What they never told you

Fact #1: You cannot access properties with names that are not legal variable names easily

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

Fact #2: You can access such properties with curly brace syntax

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

Fact #3: But not if the property name is all digits!

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

Live example.

Fact #4: Well, unless the object didn't come from an array in the first place.

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

Live example.

Pretty intuitive, don't you agree?

What you can do

Option #1: do it manually

The most practical approach is simply to cast the object you are interested in back into an array, which will allow you to access the properties:

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

Unfortunately, this does not work recursively. So in your case you 'd need to do something like:

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

Option #2: the nuclear option

An alternative approach would be to write a function that converts objects to arrays recursively:

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

However, I 'm not convinced that this is a better option across the board because it will needlessly cast to arrays all of the properties that you are not interested in as well as those you are.

Option #3: playing it clever

An alternative of the previous option is to use the built-in JSON functions:

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

The JSON functions helpfully perform a recursive conversion to array without the need to define any external functions. However desirable this looks, it has the "nuke" disadvantage of option #2 and additionally the disadvantage that if there is any strings inside your object, those strings must be encoded in UTF-8 (this is a requirement of json_encode).

like image 180
Jon Avatar answered Oct 19 '22 13:10

Jon


Just wanted to add to Jon's eloquent explanation the reason why this fails. It's all because when creating an array, php converts keys to integers — if it can — which causes lookup problems on arrays which have been cast to objects, simply because the numeric key is preserved. This is problematic because all property access options expect or convert to strings. You can confirm this by doing the following:

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

Which would output:

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

So the object has two property keys, one numeric (which can't be accessed) and one string based. This is the reason why Jon's #Fact 4 works, because by setting the property using curly braces means you always define a string-based key, rather than numeric.

Taking Jon's solution, but turning it on its head, you can generate an object from your array that always has string-based keys by doing the following:

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

From now on you can use either of the following because access in this manner always converts the value inside the curly brace to a string:

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

Good old illogical PHP...

like image 43
Pebbl Avatar answered Oct 19 '22 11:10

Pebbl


For PHP 7

Accessing Object properties having numbers as property name. Mostly needed after casting array to object.

    $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
like image 3
umesh kadam Avatar answered Oct 19 '22 13:10

umesh kadam


If an object begins with @ like:

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

You have to use:

print_r($parent_object->attributes());

because $parent_object->{'@attributes'} or $parent_object['@attributes'] won't work.

like image 2
Zydnar Avatar answered Oct 19 '22 13:10

Zydnar