0

In class a I have a setter defined. In class b, which extends class a, there is a private variable that the class a will therefore not be able to see. The setter in class a in this code will never set the variable test to a value different than the initial one, because it cannot reach it. If you run this code, for case A it will output 0.

If you run case B however, you will get an Exception saying that the property test2 does not exist.

<?php

error_reporting(E_ALL);
ini_set('display_errors', true);

class a {
    public function __set($prop, $value) {
    if((!property_exists($this, $prop))) {
      $className = get_called_class();
      throw new Exception("The property `{$prop}` in `{$className}` does not exist");
    }
    $this->$prop = $value;
    return true;
  }
}

class b extends a {
    private $test = 0;

    public function getTest() {
        return $this->test;
    }
}

// Case A
$b = new b;
$b->test = 1;
echo $b->getTest();

// Case B
$b = new b;
$b->test2 = 2;

My question is, if the class a doesn't actually get to see the variable test and will not be able to set its value, why don't I get any kind of error, exception, warning or even a tiny little notice?

This is a situation that just happened to me in a real project and it was hard to find due to no error being generated and the code logically looking correct. So how do I prevent this kind of mistakes in the future?

Digital Ninja
  • 3,415
  • 5
  • 26
  • 51

1 Answers1

0

Since class b extends class a, it inherits the __set() method from class a. This means when you try and set a property on b it's b executing the __set code. You can test this out by echoing your get_called_class() value outside of the property exists

Jay Gilford
  • 15,141
  • 5
  • 37
  • 56
  • Then why doesn't case A echo `1`? Class `b` should have set its own private property to `1` and then echoed `1`, but instead it echoes `0`. – Digital Ninja Feb 02 '15 at 08:55
  • `__set` is only called when a property doesn't exist. Since `$test` is there, the class attempts to set the value without `__set` but can't as it's private – Jay Gilford Feb 02 '15 at 09:09
  • Well that's kind of what I said in my original post, but the question was in fact if I can do something to prevent these kinds of mistakes in the future, since there is no warning or exception being generated. – Digital Ninja Feb 02 '15 at 09:22
  • Ah, I see what you mean sorry. Yeah, because you've used `__set()` you don't get the "Can't access private property $test" that you would if it weren't there. Therefore you'll need to test if the current classes $test property is private in the `__set()` method yourself. This is best done with the [Reflection properties](http://php.net/manual/en/reflectionclass.getproperties.php) – Jay Gilford Feb 02 '15 at 14:16