phpexceptiontry-catchaopcross-cutting-concerns

How can I hide ugly implementation details (i.e. try/catch blocks)?


I am adding exception handling to my PHP code. It seems that I end up with lots of sparse blocks that do exception handling and by their sheer bulkiness hide the actual production code that is being run. For example:

function loadProduct($id)
{
    $product = new ProductRecord();

    try 
    {
        $data = $product->loadFromDatabase($id);
    }
    catch (\BadFunctionCallException $e)
    {
        $error = true;
    }        

    return $data;
}

the actual payload of the above function is to return the $data. Without the exception handling it could be a 2-line function:

function loadProduct($id)
{
    $product = new ProductRecord();
    return $product->loadFromDatabase($id);
}

One way to hid this is to use Factory Method, such as:

function loadProduct($id)
{
    $product = new ProductRecord();
    $factory = new ProductFactory($product);
    return $factory->loadProduct($id);  //inside loadProduct I can put try/catch block
}

Here I am adding a whole new (factory) class and another line of code in my function to hide my exception handling. With proper care I think this will work and still look good (i.e. I can initialize my factory inside the constructor, thus moving it out of the function-level code, so it can be a good option). But is that the best?

In other words, my question is -- how can I use Exception Handling in my code without burying my actual payload into the sparseness of try/catch blocks?


Solution

  • Here is an example, how to solve your issue with Go! AOP framework and Around advice:

    /**
     * This advice intercepts an execution of some methods
     *
     * Logic is pretty simple: we wrap an original method with our advice
     * and catch all exceptions in one place.
     *
     * @param MethodInvocation $invocation Invocation
     *
     * @Around("execution(public SomeClassName->*(*)")
     */
    public function aroundPublicMethods(MethodInvocation $invocation)
    {
        try {
            $result = $invocation->proceed(); // invoke original method
        } catch (\Exception $e) {
            $result = $e; // exception will be returned as a result to method call
        }
    
        return $result;
    }
    

    That's it.