08.07.2007 / Object-oriented PHP :: A guide for fellow ISys junkies
Protecting your class variables
You’ve probably heard that PHP is a very relaxed language, and that is definitely true. Let’s take a look at an example of the extremely relaxed possibilities of PHP.
1 2 3 4 5 6 | class MyClass { } $myObject = new MyClass(); $myObject->whatToSay = "Woot!"; echo $myObject->whatToSay; |
The crazy thing is that it works. Even though MyClass is initially just an empty class, we’re still able to set random variables inside it and pull them out again. This probably isn’t the greatest practice and could lead to some extremely frustrating debugging later on. To restrict getting and setting variables to only the variables which have been declared in the class as publicly available, we will take advantage of the PHP __get() and __set() functions. Here’s how:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class MyClass { public function __get($var_name) { trigger_error("Class '" . get_class($this) . "' does not have member '$var_name' publicly available", E_USER_ERROR); } public function __set($var_name, $var_value) { trigger_error("Class '" . get_class($this) . "' does not have member '$var_name' publicly available", E_USER_ERROR); } } $myObject = new MyClass(); $myObject->whatToSay = "Woot!"; echo $myObject->whatToSay; |
To clarify, the __get() and __set() functions are what are called “magic functions” in PHP. Just like the __construct() method (which is also a magic function,) they are “magically” called when they should be. In the case of the __get() and __set() methods, they are magically called when something is trying to get or set a class variable (respectively) that has not been declared as public. When I mistakingly try to get or set a class variable that hasn’t been declared as public, I would prefer my application throw an error and kill my application rather than possibly dealing with dirty data, so in my __get() and __set() functions I throw a fatal error using PHP’s triggor_error() function. In our example, we try to set a class variable named whatToSay that doesn’t actually exist, therefore our action matches the criteria of the __set() magic function and it gets triggered. When we execute our page, we’ll get the following error:
Fatal error: Class 'MyClass' does not have member 'whatToSay' publicly available in /mnt/backside/vol/navyblue/spunky/aaronius/aaronhardy.com/php_sandbox/index.php on line 7
Again, this is what I want. I’d much rather know now than later that I did something I shouldn’t have.
Note that if you want to protect your variables as I’ve shown, you’ll want to use our __get() and __set() methods on every class that you create. For simplicity, I may not use them in later examples in this tutorial, but I’d still recommend you use them in your actual production code. Also keep in mind that most PHP programmers do not implement the __get() and __set() methods, but that doesn’t mean it’s a bad idea.
Protecting your class variables - Stepping it up a notch
While the protection we’ve already given our class variables is better than it was, oftentimes it’s just not enough. Remember during INTEX II when we had to write all the getters and setters for our class variables? This technique is called “encapsulation” or “information hiding,” and there are good reasons for it. Most importantly in my view, encapsulation can be used to validate and/or modify arguments before setting class variables or for doing similar modification before sending class variables back out of the object. For more information on encapsulation, I’d highly suggest reading John Reynold’s article entitled How not to teach programming: Getter and Setter Methods. I won’t go into depth about when encapsulation should or should not be used as it’s still a fairly debated issue, but let’s just see how it works in PHP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class MyClass { private $whatToSay; public function setWhatToSay($whatToSay) { $this->whatToSay = $whatToSay; } public function getWhatToSay() { return $this->whatToSay; } public function __get($var_name) { trigger_error("Class '" . get_class($this) . "' does not have member '$var_name' publicly available", E_USER_ERROR); } public function __set($var_name, $var_value) { trigger_error("Class '" . get_class($this) . "' does not have member '$var_name' publicly available", E_USER_ERROR); } } $myObject = new MyClass(); $myObject->setWhatToSay("Woot!"); echo $myObject->getWhatToSay(); |
It’s pretty similar to Java. In essence, we’re keeping our class variables private and forcing any modification of those variable through the getter and setter functions we have set up. Notice that I’ve still chosen to use my magic __get() and __set() functions because I prefer that my classes not be used for unintended purposes.
Protecting your class variables - Type hinting
PHP 5 introduced one other possibility of protecting your class variables called “type hinting.” With type hinting, we are forcing our arguments to be of a certain class. Let’s look at an example and then I’ll explain what’s going on:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class Dog { public function bark() { echo "Bark!"; } } class Cat { public function meow() { echo "Meow!"; } } class DogOwner { public function makeTheDogBark(Dog $dog) { $dog->bark(); } } $dog = new Dog(); $cat = new Cat(); $dogOwner = new DogOwner(); $dogOwner->makeTheDogBark($dog); $dogOwner->makeTheDogBark($cat); |
First things first, notice I didn’t use the __get() and __set() functions like we did before. That’s just for simplicity in showing you code, but in your production code I would still recommend you use them.
So we have three classes: Dog, Cat, and DogOwner. Within DogOwner, we have a method makeTheDogBark and inside the parenthesis it says Dog $dog. The Dog part is type hinting. It says only let variables of type Dog in for this argument. Let’s now focus on the very last two lines of our code. On the first, we try passing a dog in. The output is Bark!. On the second line, we try passing in a cat. The output in this case is:
Catchable fatal error: Argument 1 passed to DogOwner::makeTheDogBark() must be an instance of Dog, instance of Cat given, called in /mnt/backside/vol/navyblue/spunky/aaronius/aaronhardy.com/php_sandbox/index.php on line 31 and defined in /mnt/backside/vol/navyblue/spunky/aaronius/aaronhardy.com/php_sandbox/index.php on line 21
As you might have expected, our code broke because we tried passing it a cat when it was expecting a dog. Again, I’d much rather know now than later that I did something I shouldn’t have. As the error output implies, this error is catchable, which means you can do error handling with a try-catch structure just like you did in Java if you wish to handle the error in a more elegant fashion.
One final note on type hinting is that it only supports class types and arrays. In other words, you can’t hint that an argument should be a string or an integer. This is a fairly stark contrast to Java, C#, VB, and other languages that require that you declare the argument type no matter what it is.

Nice site you have here Aaron! There’s just one small point that I think you might be interested in. You mentioned that PHP doesn’t support object overloading, but it actually does. Several special methods can be set up on objects, including __get, __set, and __call. This may not be the same implementation as is found in other languages, but it is overloading. Check it out.