Получить свойство класса PHP по строке


147

Как мне получить свойство в PHP на основе строки? Я позвоню magic. Так что же magic?

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

будет, как...

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

Ответы:


249

Как это

<?php

$prop = 'Name';

echo $obj->$prop;

Или, если у вас есть контроль над классом, реализуйте интерфейс ArrayAccess и просто сделайте это

echo $obj['Name'];

Есть ли преимущества от использования второго варианта перед первым?
Clox

2
@Clox Как правило, основное преимущество использования последнего, если у вас есть существующая система, которая использует переменную в виде массива, но вам нужна гибкость и мощность, предлагаемые объектами. Если класс реализует ArrayAccess, Countableи один из интерфейсов итератора, он практически неотличим от обычного,array()
Питер Бейли,

162

Если вы хотите получить доступ к свойству без создания промежуточной переменной, используйте {}обозначение:

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

Это также позволяет вам построить имя свойства в цикле, например:

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

9
Это единственный способ получить доступ к значению массива $this->{$property}[$name], иначе $this->$property[$name]будет
выдана

@goyote: Это зависит от значений и версии PHP. В версии 5.3 он запускает E_NOTICE, потому что свойство не может быть найдено, а не «ошибку», поскольку это все еще действующий синтаксис PHP. Возможно, $this->$property[$name]это действительно удастся, хотя, скорее всего, это ошибка. $nameмолча приводится к целому числу. В случае нечисловой строки это так 0. Затем этот строковый индекс значения $propertyиспользуется в качестве имени свойства. Если $propertyсодержит значение «abc», то это будет относиться к свойству $this->a(индекс 0). Если есть такое свойство, то это удастся.
MrWhite

@goyote: Однако в PHP 5.4 нечисловой строковый индекс не преобразуется молча в целое число 0, он вызывает E_WARNING.
MrWhite

15

То, о чем вы спрашиваете, называется переменными переменными . Все, что вам нужно сделать, это сохранить вашу строку в переменной и получить к ней доступ следующим образом:

$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
Другое дело - переменные переменные.
Ólafur Waage

2
Вопрос в том, как получить свойство класса (переменную), когда имя содержится в строке (переменной). Или я неправильно прочитал вопрос?
Matpie

8

Что-то вроде этого? Не тестировал, но должен работать нормально.

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

2
+1, не знал, что свойства объекта могут быть получены с помощью строк.
Marco Demaio

5

Просто сохраните имя свойства в переменной и используйте переменную для доступа к свойству. Как это:

$name = 'Name';

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


4

Это просто, $ obj -> {$ obj-> Name} фигурные скобки заключают свойство так же, как переменная переменная.

Это был лучший поиск. Но не решил мой вопрос, который использовал $ this. В моем случае использование фигурной скобки тоже помогло ...

пример с экземпляром получения Code Igniter

в исходном классе библиотеки называется что-то с экземпляром родительского класса

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

класс библиотеки, который должен исходить из другого класса, также с экземпляром родителей

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

2

Просто как дополнение: таким образом вы можете получить доступ к свойствам с именами, которые иначе были бы непригодны для использования.

$ x = новый класс StdClass;

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

объект (stdClass) # 1 (2) {
  ["а б"] =>
  int (1)
  ["x y"] =>
  int (2)
}
(не то чтобы вам следовало, но в случае необходимости).
Если вы хотите делать что-то еще более интересное, вам следует изучить отражение


1

В случае, если кто-то еще хочет найти глубокое свойство неизвестной глубины, я придумал следующее, без необходимости перебирать все известные свойства всех дочерних элементов.

Например, чтобы найти $ Foo-> Bar-> baz, или $ Foo-> baz, или $ Foo-> Bar-> Baz-> dave, где $ path - это строка типа '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};

}

А затем позвоните примерно так:

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

0

Вот моя попытка. В него встроены некоторые общие проверки на «глупость», чтобы вы не пытались установить или получить недоступный член.

Вы можете переместить эти проверки property_exists в __set и __get соответственно и вызвать их непосредственно в 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

Эта функция проверяет, существует ли свойство в этом классе любого из его дочерних элементов, и если да, то получает значение, в противном случае возвращает null. Итак, теперь свойства необязательны и динамичны.

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

Применение:

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

зачем редактировать: до: использовать eval (зло) после: нет eval вообще. быть старым на этом языке.


Это очень плохой совет, функция eval () - очень опасный инструмент, который сделает вас очень уязвимым для атак путем инъекций. blog.highub.com/php/php-core/php-eval-is-evil должен предоставить вам некоторую информацию.
ridecar2

3
Удалите этот ответ, и у вас будет значок!
Thermech
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.