Getters and Setters are the backbone of many PHP classes (or any programming language class), as they allow you to alter and retrieve class properties during runtime. Many well thought and powerful scripts and frameworks make use of Getters and Setters, but is there a thing as too much? Or are there better and easier alternatives? (To make it easier on me to type, and you to read, I will refer to Getters and Setters as GnS from now on.)
By now everyone should know of the Zend Framework. It's a highly customizable and robust system built with multiple components. Zend follows the pure OOP paradigm in which most, if not all classes have an abstract, an interface, and tons of GnS. For a beginner, this might look like a huge cluster of code, as well as being very large in its documentation. But for an advanced user, it could be a god send. Personally, I find Zend's use of GnS to be too much, as it can easily be trimmed down and packaged accordingly.
Before we begin, I want to outline when and how GnS should be used. GnS should be used to alter protected properties only. Why protected you ask? If a property was public, then you can just alter the property manually without the need for a median method (unless of course the method does some manipulation on the argument). If a property is private, then that property should not be altered at all during runtime, as it is data specifically generated/built by the class internally. So that leaves protected properties to act as our configurable properties.
In a typical class, when dealing with the property $_name, you would have a method getName() and setName(). Now imagine you have a class with 15+ properties; you will immediately begin to realize the scale and amount of code required to do GnS. That's where our little friends __set(), __get() and __isset() come in handy. We can easily scale down the code from 30 methods (15 for getting, 15 for setting) to 3. Take the following before and after classes:
// Using individual methods
class User {
protected $_name;
protected $_email;
public function getName() {
return $this->_name;
}
public function setName($value) {
$this->_name = $value;
}
public function getEmail() {
return $this->_email;
}
public function setEmail($value) {
$this->_email = $value;
}
}
// Using magic methods
class User {
protected $_name;
protected $_email;
public function __get($property) {
return (isset($this->{'_'. $property}) ? $this->{'_'. $property} : null);
}
public function __set($property, $value) {
if (isset($this->{'_'. $property})) {
$this->{'_'. $property} = $value;
}
}
public function __isset($property) {
return isset($this->{'_'. $property});
}
}
Does that not look a lot easier? Sure the code looks a bit "hacky", but its perfectly usable and valid code. Of course, there are a few downsides related to this approach. For example, you may want to format a string before assigning it within setName(). With the magic methods you can not do so. But that doesn't stop you from creating a setName(), along side using the magic methods. Furthermore, the get syntax is different; you simply call the property (assuming there is no $name that conflicts with $_name).
// Using individual methods
$name = $User->getName();
$User->setName('Miles');
// Using magic methods
$name = $User->name;
$User->name = 'Miles';
// Times when a set method is needed
public function setName($name) {
$this->_name = ucall($name);
}
I would like to take this a step further, as I still believe that this is too "cluttered". The next approach solves the problem of conflicting property names, as well as reducing the code required. The approach is straight forward; simply create a global $_config (or $_data, what ever suits you) property that will deal with all the getting and setting of data.
class User {
protected $_config = array(
'name' => null,
'email' => null
);
public function __get($property) {
return (isset($this->_config[$property]) ? $this->_config[$property] : null);
}
public function __set($property, $value) {
if (isset($this->_config[$property])) {
$this->_config[$property] = $value;
}
}
public function __isset($property) {
return isset($this->_config[$property]);
}
}
In the end, it really boils down to the architecture of your application, and your personal coding preferences. Each approach has its pro's and con's, but the best solution (in my mind) is combining them. You would begin by creating the global $_config property, and building the magic methods. If you ever need to customize a get or set, then you create a specific method for it.