Search code examples
phpgetter-setter

PHP magic getter by reference and by value


I have this class:

class Foo {

   private $_data;

   public function __construct(array $data){
       $this->_data = $data;
   }

   public function __get($name){
       $getter = 'get'.$name;
       if(method_exists($this, $getter)){
           return $this->$getter();
       }

       if(array_key_exists($name,$this->_data)){
           return $this->_data[$name];
       }

       throw new Exception('Property '.get_class($this).'.'.$name.' is not available');
   }

   public function getCalculated(){
      return null;
   }
}

Where getCalculated() represents a calculated property.

Now if I try the following:

 $foo = new Foo(['related' => []])
 $foo->related[] = 'Bar'; // Indirect modification of overloaded property has no effect

 $foo->calculated; // ok

But if I change the __get() signature to &__get($name) I get:

 $foo = new Foo(['related' => []])
 $foo->related[] = 'Bar'; // ok

 $foo->calculated; // Only variables should be passed by reference

I'd quite like to return $data elements by reference and getters by value in my __get(). Is this possible?


Solution

  • As the error message suggest, you need to return a variable from your getter:

    class Foo {
    
       private $_data;
    
       public function __construct(array $data){
           $this->_data = $data;
       }
    
       public function  &__get($name){
           $getter = 'get'.$name;
           if(method_exists($this, $getter)){
               $val = $this->$getter();  // <== here we create a variable to return by ref
               return $val;
           }
    
           if(array_key_exists($name,$this->_data)){
               return $this->_data[$name];
           }
    
           throw new Exception('Property '.get_class($this).'.'.$name.' is not available');
       }
    
       public function getCalculated(){
          return null;
       }
    }