1

I'm trying to make an error handler to convert errors to JSON for my ajax requests. I've got a DB class which handles all MySql queries and which calls the following function when errors happens:

private function halt($msg)
{
    $this->Error = @mysqli_error($this->Link_ID);
    $this->Errno = @mysqli_errno($this->Link_ID);

    if ($this->throw = true) {
        throw new \Exception("Mysql Error: $msg. Error: $this->Errno ($this->Error)");
    } else if ($this->Halt_On_Error == "no") {
        return;
    }

    $this->haltmsg($msg);

    if ($this->Halt_On_Error != "report") {
        die("Session halted.");
    }
}

In my ajax script, I've got some functions like this one:

private function add()
{
    $this->changeErrorCatcher(ON);
    try {
        $obj = $this->mgr->getEmptyObject();
        foreach ($this->fields as $field) {
            if (!$this->form->vide($field) && $field != "id") {
                $name = "set" . ucfirst($field);
                $obj->$name($this->form->get($field));
            }
        }
        $this->mgr->create($obj);
        Ajax::Response(AJX_ACC, "Ok", $obj->getId());
    } catch (\Throwable $e) {
        Ajax::Response(AJX_ERR, $e->getMessage(), $e);
    }
}

changeErrorCatcher function:

private function changeErrorCatcher(bool $onOff)
{
    if ($onOff) {
        set_error_handler(function ($errno, $errstr) {
            throw new \Exception($errstr, $errno);
        }, E_ALL | E_ERROR | E_STRICT | E_USER_ERROR);
    } else {
        restore_error_handler();
    }
}

My problem is that the try/catch block in the add() function is not working: the line "$this->mgr->create($obj);" calls my DB class, so the halt() function is called when an error occurs and an Exception is thrown, but the catch block is never launched, and the text of the Exception is sent as ajax result (Making my JS fail parsing JSON)

I already tried solutions proposed here but nothing works (\Exceptions instead of Exception (even \Throwable does not work), disabling XDEBUG, changing error handler)

EDIT: I tried changing this in halt function:

if ($this->throw = true) {
    throw new \Exception("Mysql Error: $msg. Error: $this->Errno ($this->Error)");
} 

Into:

if ($this->throw = true) {
        try {
            throw new \Exception("Mysql Error: $msg. Error: $this->Errno ($this->Error)");
        } catch (\Exception $e) {
            throw new \Exception("Mysql Error: $msg. Error: $this->Errno ($this->Error)  ".$e->getTraceAsString());
        }
    }

Now I've got the stack trace in my ajax result, so the first exception is well catched but not the second... The stack trace shows me it is the line "$this->mgr->create($obj);" which throws exception.

2
  • Got a stack trace? It's likely the exception is being thrown prior to hitting your try/catch block. Commented Jul 10, 2018 at 14:06
  • Exemple ajax result: Mysql Error: Invalid SQL: INSERT INTO pays (pa_libelle, pa_code_2, pa_continent) VALUES ('Guinée', '', 'Afrique'). Error: 1062 (Duplicate entry '' for key 'index_pa_code_2') This error can only be thrown from the "$this->mgr->create($obj);" line, cause it's the only line calling my DB class Commented Jul 10, 2018 at 14:14

1 Answer 1

0

Your code is failing because mysqli is returning an error instead of an exception. Set the following in your connection constructor prior to running any queries to tell it to throw exceptions instead of errors and your code should work:

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

As your query is returning a duplicate id error, you might also consider updating the SQL statement to use INSERT IGNORE or ON DUPLICATE KEY UPDATE ... instead to handle the error at the data layer level.

Sign up to request clarification or add additional context in comments.

12 Comments

It does not change anything. See edit for precisions
The error you are receiving is a high enough priority to kill execution and cannot be supressed. You will need to handle the error appropriately instead of attempting to silence it.
Use INSERT IGNORE and then check for the count of rows changed (which will equal the number of rows provided unless a duplicate key exists).
I'm not trying to silence it but to send it as JSON object in response, in order to tell the user where is the problem, it is a manual throw() so I can't understand why it has high priority
Because mysqli mostly. If you use PDO you can cast errors as exceptions more easily.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.