Как получить доступ к нескольким свойствам с помощью волшебного метода (__get и __set)?

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

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

Есть ли кто-нибудь, кто мог бы объяснить это мне?

class myMagic2 {
    public $data;
    public $name;
    public $age;

    public function __set($item, $value) {
        $this->item = $value;
    }

    public function __get($item){
        return $this->item;
    }
}

Есть ли способ получить доступ ко всем переменным ($data, $name, $age)?


person junpos    schedule 17.07.2013    source источник
comment
вы имеете в виду получить все эти общедоступные переменные за один вызов? php.net/get_object_vars?   -  person Marc B    schedule 17.07.2013
comment
$this->$item, а не $this->item, и все ваши проблемы исчезнут :) также, может быть, property_exists() в вашем __get/__set (если я, конечно, понимаю вашу проблему).   -  person Twisted1919    schedule 17.07.2013
comment
@ Twisted1919, ты совершенно прав. была опечатка, которую я не мог найти. Спасибо за помощь   -  person junpos    schedule 08.11.2013


Ответы (2)


Когда я работаю над проектами, у меня всегда есть следующие методы:

public function __set($name, $value) 
{
    //see if there exists a extra setter method: setName()
    $method = 'set' . ucfirst($name);
    if(!method_exists($this, $method))
    {
        //if there is no setter, receive all public/protected vars and set the correct one if found
        $vars = $this->vars;
        if(array_search("_" . $name, $vars) !== FALSE)
            $this->{"_" . $name} = $value;
    } else
        $this->$method($value); //call the setter with the value
}

public function __get($name) 
{
    //see if there is an extra getter method: getName()
    $method = 'get' . ucfirst($name);
    if(!method_exists($this, $method)) 
    {
        //if there is no getter, receive all public/protected vars and return the correct one if found
        $vars = $this->vars;
        if(array_search("_" . $name, $vars) !== FALSE)
            return $this->{"_" . $name};
    } else
        return $this->$method(); //call the getter
    return null;
}

public function getVars()
{
    if(!$this->_vars)
    {
        $reflect = new ReflectionClass($this);
        $this->_vars = array();
        foreach($reflect->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED) as $var)
        {
            $this->_vars[] = $var->name;
        }
    }
    return $this->_vars;
}

Так что с ними я даю себе свободу создавать дополнительные установщики/геттеры для свойств, если я хочу манипулировать ими перед записью/возвратом. Если для свойства не существует установщика/получателя, он возвращается к самому свойству. С помощью метода getVars() вы получаете все общедоступные и защищенные свойства класса.

Свойства моего класса всегда определяются символом подчеркивания, поэтому вам, вероятно, следует это изменить.

person Tobias Golbs    schedule 17.07.2013

Вы можете следовать этому шаблону.

Примечание: в примере в посте магические методы не вызывались бы для $obj->data, $obj->name или $obj->age, потому что эти значения уже доступны как общедоступное свойство. Я изменил их, чтобы они были защищены, и изменил имя, чтобы скрыть их.

<?php
class myMagic2{
    protected $_data;
    protected $_name;
    protected $_age;

    public function __set($item, $value){
        switch($item){
            case "data":
                $this->_data = $value;
                break;
            case "name":
                $this->_name = $value;
                break;
            case "age":
                $this->_age = $value;
                break;
            default:
                throw new Exception("Property $name does not exist.");

        }

    }

    public function __get($item){
        switch($item){
            case "data":
                return $this->_data;
                break;
            case "name":
                return $this->_name;
                break;
            case "age":
                return $this->_age;
                break;
            default:
                throw new Exception("Property $name does not exist.");
                break;

        }
    }
}

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

person Orangepill    schedule 17.07.2013
comment
есть ли причина, по которой он не сделал бы что-то вроде: setter: if (property_exists($this, $name)) { $this->$name = $value; } and getter: if(property_exists($this, $name)) { return $this->$name; } ? Чистое любопытство. - person Twisted1919; 17.07.2013
comment
Никакой причины... это просто самая простая реализация, о которой я мог подумать. - person Orangepill; 17.07.2013
comment
@ Twisted1919 Это более академично, чем что-либо еще. Если вы просто используете его для получения и установки свойств через прокси, вы можете просто сделать свойства общедоступными и отказаться от магических методов. - person Orangepill; 17.07.2013