Search code examples
phpclassgetter-settermagic-methods

Through which method is the value invoked if magic getter is combined with getter


If I use it like this (outside of a class):

    $user_agent = $user->user_agent;        

Method get_user_agent() is called in constructor.

Here magic __get calls method get_user_agent and not returning value of member variable user_agent.

How to avoid that?

class user
{
    private $user_agent;


    public function __get($key)
    {
        $value = null;

        if(method_exists($this, "get_$key"))
        {
            $value = $this->{"get_$key"}();
        }
        else
        {
            $value = $this->$key;
        }

        return $value;
    }


    public function get_user_agent()
    {
        $this->user_agent = $_SERVER['HTTP_USER_AGENT'];
    }

Solution

  • You forgot to return the value after setting it:

    public function get_user_agent()
    {
        $this->user_agent = $_SERVER['HTTP_USER_AGENT'];
        return $this->user_agent;
    }
    

    But this is actually quite confusing, because you would not expect a method prefixed with 'get' to assign/define anything first before returning it. That's what __set() is for. In this case you probably even want to do it in the __construct() method:

    class user
    {
        private $user_agent;
    
        public function __construct() {
            $this->user_agent = $_SERVER['HTTP_USER_AGENT'];
        }
    
        public function __get($key) {
    
            if(method_exists($this, "get_$key"))  {
                return $this->{"get_$key"}();
            } else {
                return isset($this->{$key}) ? $this->{$key} : null;
            }
    
        }
    
        public function __set($var, $val) {
            //only allow to set existent attributes
            if( isset($this->{$var} ) ) {
                $this->{$var} = $val;
            }
        }
    
        public function get_user_agent() {
            return $this->user_agent;
        }
    }
    

    So the get-method is not the place to assign the attribute. In the example above, it is assign in the constructor. But you can change/assign it later if you want:

    $user = new user(); //constructor-method is called, $user_agent is set now
    

    But you can also set it yourself later on:

    $user->user_agent = $_SERVER['HTTP_USER_AGENT'];  //the magic __set()-method is called
    
    echo 'Your user agent is: ' . $user->user_agent;