Obtener propiedad de clase PHP por cadena


139

¿Cómo obtengo una propiedad en un PHP basada en una cadena? Lo llamaré magic. Entonces que es magic?

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

seria como...

magic($obj, 'Name', 'something');
$get = magic($obj, 'Name');

Respuestas:


241

Me gusta esto

<?php

$prop = 'Name';

echo $obj->$prop;

O, si tiene control sobre la clase, implemente la interfaz ArrayAccess y simplemente haga esto

echo $obj['Name'];

¿Algún beneficio de usar la segunda opción sobre la primera?
Clox

2
@Clox En general, el principal beneficio de usar este último si tiene un sistema existente que consume una variable de forma similar a una matriz, pero desea la flexibilidad y la potencia que ofrecen los objetos. Si una clase implementa ArrayAccess, Countabley una de las interfaces de iterador, es casi imposible de distinguir de lo normalarray()
Peter Bailey,

158

Si desea acceder a la propiedad sin crear una variable intermedia, use la {}notación:

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

Eso también le permite construir el nombre de la propiedad en un bucle, por ejemplo:

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

8
Esta es la única manera si se quiere acceder a un valor de matriz $this->{$property}[$name], de lo contrario $this->$property[$name]se generará un error
goyote

@goyote: Depende de los valores y la versión de PHP. En 5.3, desencadena un E_NOTICE porque no se puede encontrar la propiedad, en lugar de un "error", ya que sigue siendo una sintaxis PHP válida. Es posible que $this->$property[$name]realmente tenga éxito, aunque es probable que sea un error. $namese lanza silenciosamente a un número entero. En el caso de una cadena no numérica, esto es 0. Entonces este índice de cadena del valor de $propertyse usa como el nombre de la propiedad. Si $propertycontiene el valor "abc", esto se referirá a la propiedad $this->a(índice 0). Si existe tal propiedad, esto tendrá éxito.
MrWhite

@goyote: Sin embargo, en PHP 5.4, un índice de cadena no numérico no se convierte silenciosamente en el entero 0, activará un E_WARNING.
MrWhite

13

Lo que estás preguntando se llama Variable Variables . Todo lo que necesita hacer es almacenar su cadena en una variable y acceder a ella así:

$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

3
Las variables variables son otra cosa.
Ólafur Waage el

2
La pregunta es cómo obtener una propiedad de clase (variable) cuando el nombre está contenido en una cadena (variable). ¿O leí mal la pregunta?
matpie

8

¿Algo como esto? No lo he probado, pero debería funcionar bien.

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

2
+1, no sabía que se podía acceder a las propiedades del objeto utilizando cadenas.
Marco Demaio

5

Simplemente almacene el nombre de la propiedad en una variable y use la variable para acceder a la propiedad. Me gusta esto:

$name = 'Name';

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


4

Es simple, $ obj -> {$ obj-> Name} los corchetes envolverán la propiedad como una variable variable.

Esta fue una búsqueda superior. Pero no resolvió mi pregunta, que estaba usando $ this. En el caso de mi circunstancia, usar el soporte rizado también ayudó ...

ejemplo con Code Igniter obtener instancia

en una clase de biblioteca de origen llamada algo con una instancia de clase padre

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

la clase de biblioteca que necesita obtener de otra clase también con la instancia de los padres

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

2

Solo como una adición: de esta manera puede acceder a propiedades con nombres que de otro modo serían inutilizables

$ x = nueva 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)
}
(No es que debas hacerlo, pero en caso de que tengas que hacerlo).
Si quieres hacer cosas aún más elegantes, debes mirar en la reflexión


1

En caso de que alguien más quiera encontrar una propiedad profunda de profundidad desconocida, se me ocurrió lo siguiente sin necesidad de recorrer todas las propiedades conocidas de todos los niños.

Por ejemplo, para encontrar $ Foo-> Bar-> baz, o $ Foo-> baz, o $ Foo-> Bar-> Baz-> dave, donde $ path es una cadena como '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};

}

Y luego llame con algo como:

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

0

Aquí está mi intento. Tiene algunas comprobaciones comunes de 'estupidez' incorporadas, asegurándose de que no intente establecer u obtener un miembro que no esté disponible.

Puede mover esas verificaciones 'property_exists' a __set y __get respectivamente y llamarlas directamente dentro de 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";

?>

0

Lo que hace esta función es verificar si la propiedad existe en esta clase de cualquiera de sus hijos, y si es así, obtiene el valor, de lo contrario, devuelve nulo. Entonces ahora las propiedades son opcionales y dinámicas.

/**
 * 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;
}

Uso:

const CONFIG_FILE_PATH_PROPERTY = 'configFilePath';

$configFilePath = $this->getIfExist(self::CONFIG_FILE_PATH_PROPERTY);

-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);

por qué editar: antes: usando eval (evil) después: no eval en absoluto. ser viejo en este idioma


Este es un consejo muy malo, la función eval () es una herramienta muy peligrosa y te dejará enormemente vulnerable a los ataques de inyección. blog.highub.com/php/php-core/php-eval-is-evil debería darle alguna información.
ridecar2

3
¡Borra esta respuesta y tendrás una insignia!
Thermech
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.