phpexceptionmysqlitry-catch

A php mysqli exception is ignoring numerous catch blocks until the last one (which is outside any class)


I have a mysqli call ($result = $this->mysqli->query($query)) in which $query is an insert statement that generates the error: "Duplicate entry 'dt' for key 'username_UNIQUE'";. I have set the mysqli reporting mode with

\mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

The callstack at this point is about 8 methods deep, and there are several try-catch blocks along the way.

Finally there is a try-catch block in index.php, the outermost block of code. The exception seems to be ignoring all the deeper try-catch blocks, but is caught in the outermost one. Not sure if it matters, but all code blocks are in class methods except for the code in index.php.

To demonstrate this problem, I'll show you index.php and the first method called from index.php.

<?php
    define('DS',DIRECTORY_SEPARATOR);
    define('APP_START',microtime(true));
    define('ROOT_DIR',dirname(__FILE__).DS);
    define('FW_DIR',sprintf("%svendor%sfw%s",ROOT_DIR,DS,DS));
    define('APP_DIR',sprintf( '%sapp%s',ROOT_DIR,DS));
    try {
        // set up the autoloader
        require sprintf('%sbootstrap%sbootstrap.php',FW_DIR,DS);
        // next, set up the factory for all future class instantiation
        $factory = new fw\factory\ClassFactory();
        // create the app
        $app = $factory->getClass('app\app');
        // process the request
        $ob = "";
        $result = $app->go();
        // return anything in the output buffer then the application output
        echo $ob.$result;
    } catch (Exception $e) {
        die("Caught Exception in index.php: ".$e->getMessage());
    }

I have determined that the above code executes into $app->go(), but does not reach the line echo $ob.$result;.

Now here's the $app class:

<?php
namespace app;
class App extends \fw\app\App
{
    protected $trace = false;
    public function __construct(protected \fw\exception\ErrorHandler $errorhandler,
                                protected \fw\session\WebSession $session,
                                protected \app\http\RequestHandler $requesthandler,
                                protected \database\MySqlDB $db
                                ) {
        parent::__construct();
    }
    public function go(){
        try {
            $this->requesthandler->init($this->errorhandler,$this->session,$this->db);
            $result = $this->requesthandler->processrequest(false);
        } catch (Exception $e) {
            die(__METHOD__." : ".$e->__toString());
        }
        return $result;
    }
}

I have determined that the code enters $this->requesthandler->processrequest(false);. Many method calls deeper it reaches the insert statement that triggers the exception.

The output from the above is "Caught Exception in index.php: Duplicate entry 'dt' for key 'username_UNIQUE'" which clearly comes from the catch in index.php. My question is, why does the code not die in the catch block in the $app class (or any of the other try-catches deeper in the stack).


Solution

  • Your App class is specified to be using

    namespace app;
    

    which means that the classes referenced will be looked for inside this namespace. Therefore, your

    try {
        //some code
    } catch (Exception $e) {
        //some code
    }
    

    will catch any Exception object inside the app namespace, that is, any \app\Exception that might be thrown. The actual exception that is thrown is an instance of \Exception and hence it will not be caught with the catch that you have. You could have

    } catch (\Exception $e) {
    

    for example and that's the full namespace name of the Exception class whose instances you intended to catch.

    Look into aliasing and importing as well as namespaces for more information.