Отримайте властивість класу PHP за рядком


139

Як отримати властивість у PHP на основі рядка? Я зателефоную magic. То що таке magic?

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

було б як ...

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

Відповіді:


241

Подобається це

<?php

$prop = 'Name';

echo $obj->$prop;

Або якщо у вас є контроль над класом, реалізуйте інтерфейс ArrayAccess і просто зробіть це

echo $obj['Name'];

Якась перевага від використання другого варіанту над першим?
Clox

2
@Clox Як правило, головна перевага використання останньої, якщо у вас є існуюча система, яка споживає змінну подібним чином до масиву, але ви хочете, щоб гнучкість та потужність пропонували об'єкти. Якщо клас реалізує ArrayAccess, Countableі один з інтерфейсів ітератора, він в основному не відрізняється від нормальногоarray()
Пітер Бейлі

158

Якщо ви хочете отримати доступ до ресурсу без створення проміжної змінної, використовуйте {}позначення:

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

Це також дозволяє побудувати ім'я властивості в циклі, наприклад:

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

8
Це єдиний спосіб, якщо ви хочете отримати доступ до значення масиву $this->{$property}[$name], інакше $this->$property[$name]викинете помилку
goyote

@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

13

Те, про що ви запитуєте, називається Змінні змінні . Все, що вам потрібно зробити, це зберегти рядок у змінній та отримати доступ до неї так:

$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
Змінні змінні - інша річ.
flafur Waage

2
Питання полягає в тому, як отримати властивість класу (змінної), коли ім'я міститься в рядку (змінної). Або я неправильно прочитав питання?
матір

8

Щось на зразок цього? Не перевіряв, але повинен працювати чудово.

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

2
+1, не знаючи властивостей об'єкта, можна отримати доступ за допомогою рядків.
Марко Демайо

5

Просто збережіть ім'я властивості у змінній та використовуйте змінну для доступу до ресурсу. Подобається це:

$name = 'Name';

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


4

$ Obj -> {$ obj-> Name} фігурні дужки обернуть властивість так само, як і змінна змінна.

Це був найкращий пошук. Але не вирішив мого питання, що використовував $ this. У випадку моєї обставини використання фігурної дужки також допомогло ...

Приклад з кодом Igniter отримати екземпляр

в джерелі бібліотечного класу, який називається щось із екземпляром батьківського класу

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

клас бібліотеки, який потребує джерела з іншого класу також з екземпляром батьків

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

2

Як додаток: таким чином ви можете отримати доступ до властивостей з іменами, які були б інакше непридатними

$ x = новий StdClass;

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

об'єкт (stdClass) №1 (2) {
  ["a b"] =>
  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 відповідно та викликати їх безпосередньо в магії ().

<?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

Ця функція полягає в тому, щоб він перевіряє, чи існує властивість цього класу будь-якої його дитини, і якщо так, то воно отримує значення, інакше воно повертається в нулеве значення. Тож тепер властивості необов’язкові та динамічні.

/**
 * 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 (зле) після: no eval зовсім. будучи старовинною цією мовою.


Це дуже погана порада, функція eval () є дуже небезпечним інструментом і зробить вас надзвичайно вразливими до атак ін'єкцій. blog.highub.com/php/php-core/php-eval-is-evil повинен дати вам деяку інформацію.
їзда2

3
Видаліть цю відповідь, і ви отримаєте значок!
Термех
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.