Récupère la propriété de classe PHP par chaîne

139

Comment obtenir une propriété dans un PHP basée sur une chaîne? Je vais l'appeler magic. Alors qu'est-ce que c'est magic?

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

serait comme...

magic($obj, 'Name', 'something');
$get = magic($obj, 'Name');
Daniel A. White
la source

Réponses:

241

Comme ça

<?php

$prop = 'Name';

echo $obj->$prop;

Ou, si vous avez le contrôle sur la classe, implémentez l' interface ArrayAccess et faites simplement ceci

echo $obj['Name'];
Peter Bailey
la source
Y a-t-il un avantage à utiliser la deuxième option par rapport à la première?
Clox
2
@Clox Généralement, le principal avantage de l'utilisation de ce dernier si vous avez un système existant qui consomme une variable de manière tableau, mais que vous voulez la flexibilité et la puissance offertes par les objets. Si une classe implémente ArrayAccess, Countableet l'une des interfaces de l'itérateur, elle ne se distingue généralement pas d'une normalearray()
Peter Bailey
158

Si vous souhaitez accéder à la propriété sans créer de variable intermédiaire, utilisez la {}notation:

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

Cela vous permet également de créer le nom de la propriété dans une boucle par exemple:

for ($i = 0; $i < 5; $i++) {
    $something = $object->{'something' . $i};
    // ...
}
Laurent
la source
8
C'est le seul moyen si vous souhaitez accéder à une valeur de tableau $this->{$property}[$name], sinon vous $this->$property[$name]
lancerez
@goyote: Cela dépend des valeurs et de la version PHP. En 5.3, il déclenche un E_NOTICE parce que la propriété est introuvable, plutôt qu'une "erreur", car il s'agit toujours d'une syntaxe PHP valide. Il est possible que $this->$property[$name]cela réussisse, bien que ce soit probablement un bogue. $nameest converti silencieusement en un entier. Dans le cas d'une chaîne non numérique, c'est le cas 0. Ensuite, cet index de chaîne de la valeur de $propertyest utilisé comme nom de propriété. Si $propertycontient la valeur "abc", alors cela fera référence à la propriété $this->a(index 0). S'il existe une telle propriété, cela réussira.
MrWhite
@goyote: Cependant, en PHP 5.4, un index de chaîne non numérique n'est pas converti silencieusement en entier 0, il déclenchera un E_WARNING.
MrWhite
13

Ce que vous demandez s'appelle les variables variables . Tout ce que vous avez à faire est de stocker votre chaîne dans une variable et d'y accéder comme suit:

$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
matpie
la source
3
Les variables variables sont une autre chose.
Ólafur Waage
2
La question est de savoir comment obtenir une propriété de classe (variable) lorsque le nom est contenu dans une chaîne (variable). Ou ai-je mal lu la question?
matpie
8

Quelque chose comme ça? Je ne l'ai pas testé mais devrait fonctionner correctement.

function magic($obj, $var, $value = NULL)
{
    if($value == NULL)
    {
        return $obj->$var;
    }
    else
    {
        $obj->$var = $value;
    }
}
Ólafur Waage
la source
2
+1, je ne savais pas que les propriétés des objets pouvaient être accédées à l'aide de chaînes.
Marco Demaio
5

Stockez simplement le nom de la propriété dans une variable et utilisez la variable pour accéder à la propriété. Comme ça:

$name = 'Name';

$obj->$name = 'something';
$get = $obj->$name;
Jon Benedicto
la source
5

Il peut y avoir des réponses à cette question, mais vous voudrez peut-être voir ces migrations vers PHP 7

changement incompatible vers l'arrière

source: php.net

Muhammad Maulana
la source
4

C'est simple, $ obj -> {$ obj-> Name} les accolades encapsuleront la propriété un peu comme une variable variable.

C'était une recherche de premier ordre. Mais n'a pas résolu ma question, qui utilisait $ this. Dans le cas de ma situation, l'utilisation du crochet bouclé a également aidé ...

exemple avec Code Igniter get instance

dans une classe de bibliothèque source appelée quelque chose avec une instance de classe parente

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

la classe de bibliothèque qui doit s'approvisionner à partir d'une autre classe également avec l'instance des parents

echo $this->CI->{$this->someClass}->{$this->someID};
Mark Allen
la source
2

Juste comme un ajout: De cette façon, vous pouvez accéder à des propriétés avec des noms qui seraient autrement inutilisables

$ x = nouvelle StdClass;

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

objet (stdClass) # 1 (2) {
  ["a b"] =>
  int (1)
  ["x y"] =>
  int (2)
}
(pas que vous devriez, mais au cas où vous deviez le faire).
Si vous voulez faire des choses encore plus sophistiquées, vous devriez vous pencher sur la réflexion

VolkerK
la source
1

Au cas où quelqu'un d'autre voudrait trouver une propriété profonde de profondeur inconnue, j'ai trouvé ce qui suit sans avoir besoin de parcourir toutes les propriétés connues de tous les enfants.

Par exemple, pour trouver $ Foo-> Bar-> baz, ou $ Foo-> baz, ou $ Foo-> Bar-> Baz-> dave, où $ path est une chaîne comme «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};

}

Et puis appelez avec quelque chose comme:

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

Voici ma tentative. Il a quelques contrôles communs de «stupidité» intégrés, vous assurant que vous n'essayez pas de définir ou d'obtenir un membre qui n'est pas disponible.

Vous pouvez déplacer ces vérifications 'property_exists' vers __set et __get respectivement et les appeler directement dans 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";

?>
Nick Presta
la source
0

Cette fonction vérifie si la propriété existe sur cette classe de l'un de ses enfants, et si c'est le cas, elle obtient la valeur sinon elle retourne null. Alors maintenant, les propriétés sont facultatives et dynamiques.

/**
 * 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);
Mahmoud Zalt
la source
-6
$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);

pourquoi edit: before: en utilisant eval (evil) after: aucun eval du tout. être vieux dans cette langue.

r4ccoon
la source
C'est un très mauvais conseil, la fonction eval () est un outil très dangereux et vous laissera extrêmement vulnérable aux attaques par injection. blog.highub.com/php/php-core/php-eval-is-evil devrait vous donner quelques informations.
ridecar2
3
Supprimez cette réponse et vous aurez un badge!
Thermech