Anyone who has done almost any PHP that required your to make a class
of some sort probably also had to create getters and setters. If you happen
to have a lot of properties that need to have getters and setters it can become
bothersome, however using PHP’s __call magic method this can be cut down to
just a small snippet of code, here’s how.
PHP’s __call magic method allows method’s that do not exist in your class to be
called, so for instance let’s say you have the class.
<?php
class Foo {
public function Hello() {
echo "Hello, world!";
}
public function __call($name, $args) {
echo "Calling method {$name}";
}
}
?>
Now if you where to call Foo::Hello();
you would get “Hello, world!” printed
to your browser, however calling something like Foo::Bar();
would cause PHP
to send the method name and arguments to your __call method as your class
does not have an actual method name Bar. So how can we use this to our
advantage? Lets see.
I am creating a new project and I have this class which will have many properties,
some stored in an array some actual variables and I need to create getters and setters
for all of them, what to do. Well with the help of the __call magic method it is as easy
as this.
class Foo
{
private $test;
private $test2;
private $bar;
public function __construct()
{
$this->test = "";
$this->test2 = "";
$this->bar = array();
$this->bar['str'] = " world!";
}
public function __call($name, $args)
{
if(preg_match("/get/i", $name))
{
//Set the entire method name to lowercase so we don't have to mess around with
//anything incase camel case or C# like method names are being used.
$name = strtolower($name);
//Find the start and length of the get / set in the method.
$pos = strpos($name, "get") + strlen("get");
//Strip the get / set from the getter / setter method.
$name = substr($name, $pos, strlen($name) - $pos);
//Create a new reflection object from this class.
$reflection = new ReflectionClass($this);
$props = $reflection->getProperties(ReflectionProperty::IS_PRIVATE | ReflectionProperty::IS_PROTECTED);
//Loop through all the properties that we found.
foreach($props as $prop)
{
//Check if it is an array so we can search the keys in an array instead of the
//name of the property.
if(is_array($this-> {$prop->getName()}))
{
//So it's an array, does our array contain a key with the name
//that we are looking for?
if(key_exists($name, $this-> {$prop->getName()}))
return $this-> {$prop->getName()} [$name];
}
//If it is not an array then does that name match the name we are looking for?
else if($prop->getName() == $name)
return $this->$name;
}
return null;
}
//Do almost the same thing as in the get option get here but we will be setting a value
//not retreving one.
else if(preg_match("/set/i", $name))
{
$name = strtolower($name);
$pos = strpos($name, "set") + strlen("set");
$name = substr($name, $pos, strlen($name) - $pos);
$value = "";
//Make sure we actually have an argument in there.
if(count($args) >= 1)
$value = $args[0];
$reflection = new ReflectionClass(__CLASS__);
$props = $reflection->getProperties(ReflectionProperty::IS_PRIVATE | ReflectionProperty::IS_PROTECTED);
foreach($props as $prop)
{
if(is_array($this-> {$prop->getName()}))
{
if(key_exists($name, $this-> {$prop->getName()}))
$this-> {$prop->getName()} [$name] = $value;
}
else if($prop->getName() == $name)
$this->$name = $value;
}
}
}
}
$foo = new Foo();
$foo->setTest("Hello,");
echo $foo->getTest(); //Prints "Hello,"
echo $foo->getStr(); //Prints " world!"