简体   繁体   中英

How can I access a deep object property named as a variable (dot notation) in php?

There are many questions similar to this, however this is slightly different since it's about deep object property access, not just one level of depth.

Let's say I have a variable containing the string foo.bar .

$user = new User();
$user->foo = new Foo();
$user->foo->bar = "Hello World";

$variable = "foo.bar"

I would like to echo $user->foo->bar by making use of $variable :

echo $user->foo->bar

This is what I have tried so far but with no success (it says NULL ):

$value = str_replace(".", "->", $value);
echo $user->{$value};

It is very easy to reduce the object path using variable property notation ( $o->$p ):

$path = 'foo.bar';
echo array_reduce(explode('.', $path), function ($o, $p) { return $o->$p; }, $user);

This could easily be turned into a small helper function.

A little improvement added to @deceze post.

This allow handling cases where you need to go through arrays also.

$path = 'foo.bar.songs.0.title';
echo array_reduce(explode('.', $path), function ($o, $p) { return is_numeric($p) ? $o[$p] : $o->$p; }, $user);

Edit:

And if you have PHP 7+, then the following will safely return null if a property's name is mistyped or if it doesn't exist.

$path = 'foo.bar.songs.0FOOBAR.title';
echo array_reduce(explode('.', $path), function ($o, $p) { return is_numeric($p) ? ($o[$p] ?? null) : ($o->$p ?? null); }, $user);

There is no easy way to do it.

Fortunately though, lots of people want to do this, so there's libraries that support it, like Symfony's PropertyAccessor:

http://symfony.com/doc/current/components/property_access.html

I am posting this as a compliment to an answer ( How to write getter/setter to access multi-level array by key names? ) that does the same for arrays.

Create the $path array via explode() (or add to the function), then use references.

$path = explode('.', $variable);

Getter

function get($path, $object) {
    $temp = &$object;

    foreach($path as $var) {
        $temp =& $temp->$var;
    }
    return $temp;
}

$value = get($path, $user);

And of course the evil eval() , not recommended:

$value = str_replace('.', '->', $variable);
eval("echo \$user->$value;");

You can use my JSON package using Composer:

composer require machitgarha/json

For example:

$userJson = new MAChitgarha\Component\JSON(new User());

$userJson->set("foo", new Foo());
$userJson->set("foo.bar", "Hello World");

$userJson->get("foo.bar"); // Hello World 

I have written a recursive algorithm for finding all the values ​​of properties.

    public function findAttributeFromJson($json,$attributeFind,$assignAttribute)
{
    if(!is_array($json)) return $assignAttribute;

    $properties = array_keys($json);

    foreach ($properties as $value) {
        if($value === $attributeFind)
        {
            $assignAttribute[count($assignAttribute)] = $json[$value];
        }
        $assignAttribute = $this->findAttributeFromJson($json[$value],$attributeFind,$assignAttribute);
    }
    return $assignAttribute;
}

And use it

        $arrResult = array();
        $arrResult = $this->findAttributeFromJson($arrFind,$properties,$arrResult );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM