Lets say you write two classes, a parent (P) and a child (C) and expect that future children will be written, that uses exceptions for error handling. As you start using the classes you realize that there are times when it'd be better if it just returned false instead of throwing an exception. So you create a throw/nothrow toggle ability.
Ok some constraints:
You are lazy and don't want to have the throw/nothrow logic in every function.
You are lazy and don't want to have the throw/nothrow logic in every child class.
PHP 5+ because PHP 4 is dead and sucks donkey balls for OOP
Well I found a way. It probably violates the natural order of things but meh
First I am going to go backwards and look at the child classes first. First write the functions normally using exceptions and test normally. After all the testing is done change the functions from public to protected. Making it protected means that outside code can't access the function but internal code can.
Next the parent. The first thing to realize that even when you are in a parent's method $this still refers to the child object. The parent methods can access the child's public and protected methods but not its private methods.
In the parent class add the nothrow variable and toggling method(s). Now the work horse is going to be the magic method
__call(). __call is invoked whenever you call an inaccessible method on an object. It takes two parameters: the name of the method called and an array of the parameters. In __call() you can use call_user_func_array() to call the method and since you are doing it from inside the parent you can access the child's protected methods. So using a simple if/else and try/catch you can implement the throw/nothrow functionality.
Now a catch I found was that if the method called is private or otherwise inaccessible to the parent you'd get infinite recursion. So to counter then you can use reflection to get a list of the child methods and make a list of all the protected functions. Then in __call you simply check to see if the method called is in the list.
Ok code time:
<?php
class p
{
private $method_cache = null;
public function __construct()
{
$ref = new ReflectionClass($this);
$methods = $ref->getMethods();
$callable = array();
foreach($methods AS $method)
{
if ($method->isProtected())
{
$callable[] = $method->name;
}
}
$this->method_cache = $callable;
}
public function __call($name, $arguments)
{
if (!in_array($name, $this->method_cache))
return false;
if ($this->throwErrors)
return call_user_func_array(array($this, $name), $arguments);
else
{
try
{
return call_user_func_array(array($this, $name), $arguments);
}
catch (Exception $e)
{
$this->setLastError($e);
return false;
}
}
}
}
class c extends p
{
protected function foo()
{
echo "foo\n";
}
private function bar()
{
echo "bar\n";
}
}
$c = new c();
$c->foo();
$c->bar();