RSS Feed

Peter Goodman's blog about PHP, Parsing Theory, C++, Functional Programming, Applications,

Yielding Control to a Different Controller

Recently I've implemented a very nice feature in PINQ: the ability to yield control to a different controller. The way it works is by throwing a specific exception and the catch for that exception is within a do-while loop. Inside that loop is the code that parses a route, instantiate a controller and dispatch to an action. The catch changes the route to parse and tells the loop to iterate one more time, thus allowing the programmer to change the controller/action being executed.

This feature's main use case is error handling. With a proper error controller set up, such as the one below:


class ErrorController extends PinqController {    
    public $layout_file = 'error';
    public function ANY_403() { set_http_status(403); }
    public function ANY_404() { set_http_status(404); }
    public function ANY_405() { set_http_status(405); }
    public function ANY_500() { set_http_status(500); }

I can then do: yield('/error/404/index.html') for example, or more easily do yield(ERROR_404);. This feature allows me to move the presentation logic for errors into controllers that are under the control of the programmer (ie: in the application directory) and also not make common errors not something that needs to be handled separately of the rest of the program.

Another use case is extending the class that causes this change in control flow. For example, my DatabaseException class now causes an error 500 when thrown as usual. Here is the code to do that:


class DatabaseException extends YieldControlException {
    public function __construct($message) {
        $this->message = $message;

I think this is an extremely sweet solution to the problem of gracefully handling certain kinds of errors.