Assume we have this code:
class SomeClass{
private $somePrivateField;
public function __get($name){
$function = "get".ucfirst($name);
return $function;
}
public function __set($name,$value){
$function = "set".ucfirst($name);
return $function($value);
}
public function __call($name, $arguments) {
//if function being called is getSomething
//getThat private/protected field if exists and return
//if not raise exception
// similar for setSomething...
}
}
This is a passage from some tutorial:
The __get() method accepts an argument that represents the name of the property being set. In the case of $obj->property, the argument will be property.
Our __get() method then converts this to getProperty, which matches the pattern we defined in the __call() method. What this means is that $obj->property will first try to set a public property with the same name, then go to __get(), then try to call the public method setProperty(), then go to __call(), and finally set the protected $_property.
So when I say somewhere in my code
$obj->property
I can understand it tried to access the public field first.. Why does it go to __get() first? Why not __set() ? Why does it go to __set() then?
Can someone please explain? Thanks...
__get()
will only ever return a string comprising the name of a function that probably doesn't exist.__set()
actually calls the function whose name it constructs, but I'm having trouble determining why because...__call()
seemingly has to determine if the function it's calling is actually a "setter" or "getter" function, which is the entire point of __get()
and __set()
in the first place.$obj->property
is a non-sensical fragment of code that does not actually do anything on it's own.// assuming $obj->property is declared as private, or does not exist in the class.
$var = $obj->property; // invokes __get('property')
$obj->property = $var; // invokes __set('property', $var)
$obj->someFunction($var1, $var2, ...);
// invokes __call('someFunction', array($var1, $var2, ...)), but only if
// the specified function is private, or otherwise does not exist.
To re-write the example code so that it makes some semblance of sense:
class SomeClass{
private $somePrivateField;
public function __get($name){
if( isset($this->$name) ) {
return $this->$name;
} else {
Throw new Exception("Object property $name does not exist.");
}
}
public function __set($name,$value){
if( isset($this->$name) ) {
$this->$name = $value;
} else {
Throw new Exception("Object property $name does not exist.");
}
}
}
$obj = new SomeClass();
$obj->somePrivateField = $var; // uses __set()
$var = $obj->somePrivateField; // uses __get()
Using __call()
all is rarely necessary, certainly not for the given example.
Or if you would like to be able to set/get private/public properties without having to explicitly declare them first:
class SomeClass{
private $properties = array();
public function __get($name){
if( isset($this->properties['name']) ) {
return $this->properties['name'];
} else {
Throw new Exception("Object property $name does not exist.");
}
}
public function __set($name,$value){
$this->properties[$name] = $value;
}
// it's also a good idea to define __isset() and __unset() in this case as well
public function __isset($name) {
return isset($this->properties['name']);
}
public function __unset($name) {
return unset($this->properties['name']);
}
}