Question

How do I get a property in a PHP based on a string? I'll call it magic. So what is magic?

$obj->Name = 'something';
$get = $obj->Name;

would be like...

magic($obj, 'Name', 'something');
$get = magic($obj, 'Name');
Was it helpful?

Solution

Like this

<?php

$prop = 'Name';

echo $obj->$prop;

Or, if you have control over the class, implement the ArrayAccess interface and just do this

echo $obj['Name'];

OTHER TIPS

If you want to access the property without creating an intermediate variable, use the {} notation:

$something = $object->{'something'};

That also allows you to build the property name in a loop for example:

for ($i = 0; $i < 5; $i++) {
    $something = $object->{'something' . $i};
    // ...
}

What you're asking about is called Variable Variables. All you need to do is store your string in a variable and access it like so:

$Class = 'MyCustomClass';
$Property = 'Name';
$List = array('Name');

$Object = new $Class();

// All of these will echo the same property
echo $Object->$Property;  // Evaluates to $Object->Name
echo $Object->{$List[0]}; // Use if your variable is in an array

Something like this? Haven't tested it but should work fine.

function magic($obj, $var, $value = NULL)
{
    if($value == NULL)
    {
        return $obj->$var;
    }
    else
    {
        $obj->$var = $value;
    }
}

Just store the property name in a variable, and use the variable to access the property. Like this:

$name = 'Name';

$obj->$name = 'something';
$get = $obj->$name;

It is simple, $obj->{$obj->Name} the curly brackets will wrap the property much like a variable variable.

This was a top search. But did not resolve my question, which was using $this. In the case of my circumstance using the curly bracket also helped...

example with Code Igniter get instance

in an sourced library class called something with a parent class instance

$this->someClass='something';
$this->someID=34;

the library class needing to source from another class also with the parents instance

echo $this->CI->{$this->someClass}->{$this->someID};

There might be answers to this question, but you may want to see these migrations to PHP 7

backward incompatible change

source: php.net

Just as an addition: This way you can access properties with names that would be otherwise unusable

$x = new StdClass;

$prop = 'a b'; $x->$prop = 1; $x->{'x y'} = 2; var_dump($x);

object(stdClass)#1 (2) {
  ["a b"]=>
  int(1)
  ["x y"]=>
  int(2)
}
(not that you should, but in case you have to).
If you want to do even fancier stuff you should look into reflection

In case anyone else wants to find a deep property of unknown depth, I came up with the below without needing to loop through all known properties of all children.

For example, to find $Foo->Bar->baz, or $Foo->baz, or $Foo->Bar->Baz->dave, where $path is a string like 'foo/bar/baz'.

public function callModule($pathString, $delimiter = '/'){

    //split the string into an array
    $pathArray = explode($delimiter, $pathString);

    //get the first and last of the array
    $module = array_shift($pathArray);
    $property = array_pop($pathArray);

    //if the array is now empty, we can access simply without a loop
    if(count($pathArray) == 0){
        return $this->{$module}->{$property};
    }

    //we need to go deeper
    //$tmp = $this->Foo
    $tmp = $this->{$module};

    foreach($pathArray as $deeper){
        //re-assign $tmp to be the next level of the object
        // $tmp = $Foo->Bar --- then $tmp = $Bar->baz
        $tmp = $tmp->{$deeper};
    }

    //now we are at the level we need to be and can access the property
    return $tmp->{$property};

}

And then call with something like:

$propertyString = getXMLAttribute('string'); // '@Foo/Bar/baz'
$propertyString = substr($propertyString, 1);
$moduleCaller = new ModuleCaller();
echo $moduleCaller->callModule($propertyString);

Here is my attempt. It has some common 'stupidity' checks built in, making sure you don't try to set or get a member which isn't available.

You could move those 'property_exists' checks to __set and __get respectively and call them directly within magic().

<?php

class Foo {
    public $Name;

    public function magic($member, $value = NULL) {
        if ($value != NULL) {
            if (!property_exists($this, $member)) {
                trigger_error('Undefined property via magic(): ' .
                    $member, E_USER_ERROR);
                return NULL;
            }
            $this->$member = $value;
        } else {
            if (!property_exists($this, $member)) {
                trigger_error('Undefined property via magic(): ' .
                    $member, E_USER_ERROR);
                return NULL;
            }
            return $this->$member;
        }
    }
};

$f = new Foo();

$f->magic("Name", "Something");
echo $f->magic("Name") , "\n";

// error
$f->magic("Fame", "Something");
echo $f->magic("Fame") , "\n";

?>

What this function does is it checks if the property exist on this class of any of his child's, and if so it gets the value otherwise it returns null. So now the properties are optional and dynamic.

/**
 * check if property is defined on this class or any of it's childes and return it
 *
 * @param $property
 *
 * @return bool
 */
private function getIfExist($property)
{
    $value = null;
    $propertiesArray = get_object_vars($this);

    if(array_has($propertiesArray, $property)){
        $value = $propertiesArray[$property];
    }

    return $value;
}

Usage:

const CONFIG_FILE_PATH_PROPERTY = 'configFilePath';

$configFilePath = $this->getIfExist(self::CONFIG_FILE_PATH_PROPERTY);
$classname = "myclass";
$obj = new $classname($params);

$variable_name = "my_member_variable";
$val = $obj->$variable_name; //do care about the level(private,public,protected)

$func_name = "myFunction";
$val = $obj->$func_name($parameters);

why edit: before : using eval (evil) after : no eval at all. being old in this language.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top