The following code implements "dynamic" getter and setter methods for controlling class properties with the help of method overloading. Again, read the source code. Don\'t be afraid if you are unable to understand all of it--an explanation follows the code.
<?php
class DynamicGetterSetter {
private $name = "Martin Jansen";
private $starbucksdrink = "Caramel Cappuccino Swirl";
function __call($method, $arguments) {
$prefix = strtolower(substr($method, 0, 3));
$property = strtolower(substr($method, 3));
if (empty($prefix) || empty($property)) {
return;
}
if ($prefix == "get" && isset($this->$property)) {
return $this->$property;
}
if ($prefix == "set") {
$this->$property = $arguments[0];
}
}
}
$class = new DynamicGetterSetter;
echo "Name: " . $class->getName() . "n";
echo "Favourite Starbucks flavour: " . $class->getStarbucksDrink() . "nn";
$class->setName("John Doe");
$class->setStarbucksDrink("Classic Coffee");
echo "Name: " . $class->getName() . "n";
echo "Favourite Starbucks flavour: " . $class->getStarbucksDrink() . "nn";
?>
As you can see, the two class properties $name and $starbucksdrink are both private, which means that nothing can access those properties directly from outside the class. In object-oriented programming, it\'s common to implement public getter and setter methods for accessing and modifying the values of nonpublic properties. Implementing those methods is a rather monotonous task and, while easy to achieve using copy and paste, still consumes time and energy.
Method overloading is an easy way to circumvent this task. Instead of implementing getters and setters for every single property, the above code implements only the __call() wildcard method. This means that when calling an undefined getter or setter like setName() or getStarbucksdrink(), PHP does not abort with a fatal error, but instead executes (or delegates to) the magic __call() method.
Those are the basics, but __call() is more complex.
A look inside __call()
The first argument of __call() is the name of the original, unfound method (setName, for example). The second one is a one-dimensional, numerically indexed array containing all of the arguments for the original method. Calling an undefined method with two arguments, "Martin" and 42, will result in the following array:
$class->thisMethodDoesNotExist("Martin", 42);
// leads to the second argument of __call():
Array
(
[0] => Martin
[1] => 42
)
Inside __call(), an evaluation takes place if the name of the original method starts with get or set in order to figure out whether the code called a getter or a setter. Additionally, the method looks at the rest of the method name (minus the first three characters), because this string marks the name of the property to which the "virtual" getter or setter refers.
If the method name indicates a getter or setter, the method must either return the value of the corresponding property or set its value to the first argument of the original method. Otherwise it does nothing, continuing the programming execution as if nothing had happened.
The Achieved Goal
In essence, this is a way that allows code to dynamically call arbitrary getter and setter methods for arbitrary properties. This becomes especially handy in situations such as developing an application prototype in a short period of time: instead of wasting man-hours on implementing getters and setters, developers can focus on modeling the API and getting the application\'s fundamentals right. Outsourcing __call() into an abstract class even allows you to reuse the code during the development phase of all your future PHP projects!
Disadvantages
Where there is light, there is also shadow. Some disadvantages are here too: bigger projects likely use a tool such as phpDocumentor to keep track of the API structure. Using the above trick for dynamic methods, all getter and setter methods will of course not appear in any automatically generated documentation, because the "stupid" generators cannot figure out that __call() is a wildcard for all get* and set* methods.
Another disadvantage is the fact that code outside of the class has access to every private property. When using real getter and setter methods, it\'s possible to distinguish between private properties that external code may access and really private properties that are totally invisible from the outside. With method overloading enabled, this distinction is no longer possible, because there are virtual getter and setter methods for everything.
Conclusion
Congratulations if you\'ve made it here! Now that you are aware of the possibilities that overloading offers, you have something at your fingertips that allows you to save quite a bit of time and work in the early (and probably also later) stages of your future projects. Really, what\'s better than telling your boss that you\'ve finished the prototype of that next project long before it\'s due?