kporter
kporter

Reputation: 2768

__get and __set not behaving as expected

<?php
class BaseClass {
  protected $data = array("foo" => 0, "bar" => 0, "baz" => 0);

  public function __set($name, $value) {
    if( array_key_exists($name, $this->data)){
      $func = "set_$name";
      return call_user_func_array(array($this,$func),array($value));
    }
  }


  public function __get($name) {
    if ( array_key_exists($name, $this->data)){
      $func = "get_$name";
      return call_user_func_array(array($this,$func),array());
    }
  }

  public function __call($method, $args) {
    if (method_exists($this,$method)) {
      return call_user_func_array(array($this,$method),$args);
    }

    if (substr($method, 0, 4) == 'set_'){
      $var_name = substr($method, 4);
      if (!(array_key_exists($var_name, $this->data))){ 
        return FALSE;
      }
      $this->data[$var_name] = $args[0];
      return TRUE;
    }

    if (substr($method, 0, 4) == 'get_'){
      $var_name = substr($method, 4);
      if (!(array_key_exists($var_name, $this->data))){ 
        return FALSE;
      }
      return $this->data[$var_name];
    }
  }
}

class SubClass extends BaseClass {
  protected $baz_changed = FALSE;

  public function set_baz($value) {
    if ($value != $this->baz){
      print "\n\nthis->data BEFORE SET:  ";
      print_r($this->data);
      print "\n\nthis->baz:  ";
      print_r($this->baz);
      print "\n\nPASSED baz:  ";
      print_r($value);
      $this->baz = $value;
      print "\n\nbaz AFTER SET:  ";
      print_r($this->baz); // appears it was set 
      print "\n\nDATA ARRAY:  ";
      print_r($this->data);  // but it wasn't ... what gives? 
      $this->baz_changed = TRUE;
    }
  }
}

$sc = new SubClass();
$sc->foo = 1;
print "\n\$sc->foo = $sc->foo\n";
$sc->baz = 5;
print "\$sc->baz = $sc->baz\n";
?>

I get the following results are not as I would have expected:

 $sc->foo = 1


 this->data BEFORE SET:  Array (
     [foo] => 1
     [bar] => 0
     [baz] => 0 )


 this->baz:  0

 PASSED baz:  5

 baz AFTER SET:  5

 DATA ARRAY:  Array (
     [foo] => 1
     [bar] => 0
     [baz] => 0 ) $sc->baz = 5

As you can see, it appears that baz is set but it never gets set in the data array. Can anyone explain why and how to fix this?

EDIT: Fixed formatting of the results and adding more context to this code section because stackoverflow is complaining I do not have enough.

EDIT: Just noticed that at the end it says $sc->baz = 5. But the data array isn't updated. This is not expected I would rather that the data array version of baz were updated. Instead of a new instance variable created in SubClass.

Upvotes: 0

Views: 321

Answers (2)

Loken Makwana
Loken Makwana

Reputation: 3848

It's behaving correctly, when you do $sc->baz = 5; it finds that set_baz method is there and executes this line $this->baz = $value; and sets the value of baz property

Assume if the __get and __set working on in the class too then how you access $this->data in the class?

Upvotes: 0

user229044
user229044

Reputation: 239291

You're attempting to recursively call __set, and PHP specifically disallows this.

  • In __set, you call set_baz
  • In set_baz, you do $this->baz = 5
  • This would invoke __set, except PHP prevents this from happening. If it didn't, your program would never end.

You cannot trigger __set if you're already within __set. Instead, you are dynamically defining a new member variable called $this->baz exactly as if __set did not exist. If you var_dump your object, you will find that it now contains both $data and $baz members.

Inside set_baz, you need to explicitly write to $this->data. You cannot write to $this->baz.

Upvotes: 2

Related Questions