8

http://php.net/manual/en/pdo.error-handling.php

PDO::ERRMODE_WARNING

In addition to setting the error code, PDO will emit a traditional E_WARNING message. This setting is useful during debugging/testing, if you just want to see what problems occurred without interrupting the flow of the application.

PDO::ERRMODE_EXCEPTION

In addition to setting the error code, PDO will throw a PDOException and set its properties to reflect the error code and error information. This setting is also useful during debugging, as it will effectively "blow up" the script at the point of the error, very quickly pointing a finger at potential problem areas in your code (remember: transactions are automatically rolled back if the exception causes the script to terminate).

Exception mode is also useful because you can structure your error handling more clearly than with traditional PHP-style warnings, and with less code/nesting than by running in silent mode and explicitly checking the return value of each database call.

However, the code:

$connection = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', '***');
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$connection->query('SET wait_timeout=1;');
sleep(2);

try {
    $connection->query('SELECT 1;');
} catch (\Exception $e) {
    echo sprintf('Caught %s exception: %s', get_class($e), $e->getMessage()) . PHP_EOL;
}

triggers warnings:

PHP Warning:  PDO::query(): MySQL server has gone away in pdo.php on line 13
PHP Warning:  PDO::query(): Error reading result set's header in pdo.php on line 13
Caught PDOException exception: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away

IMPORTANT: The question is not about problem with MySQL server gone, but about PDO error handling.

UPDATE: Warnings triggered in all three modes: ERRMODE_SILENT, ERRMODE_WARNING, ERRMODE_EXCEPTION

PHP 7.2.1 (cli) (built: Jan  5 2018 17:34:14) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2017 Zend Technologies
Community
  • 1
  • 1
Sergei Kasatkin
  • 385
  • 2
  • 11
  • 3
    @B001 He's not asking how to solve error 2006 (please note that the sole purpose of the code shared is precisely to *triggger* that error) but how to prevent PDO from throwing an exception **and** a warning. – Álvaro González Feb 08 '18 at 10:07
  • (Which of those eleven lines of code is line 13 exactly?) What you quoted only says that it was a better alternative to handle errors, but I don’t read it as saying it would suppress the PHP warnings this might cause as well. – CBroe Feb 08 '18 at 10:10
  • it's the line with second query: $connection->query('SELECT 1;'); – Sergei Kasatkin Feb 08 '18 at 10:11
  • @CBroe, indeed, docs don't say about suppressing, but obviously ERRMODE_WARNING makes impression, that warnings should be triggered only in that mode. BTW, ERRMODE_SILENT still triggers warnings – Sergei Kasatkin Feb 08 '18 at 10:17
  • No, ERRMODE_WARNING makes it trigger PHP warnings _only_, instead of throwing an exception. As the manual describes it, _"This setting is useful during debugging/testing, if you just want to see what problems occurred without interrupting the flow of the application."_ // Can you point out which line in the code shown is supposed to be line 13? – CBroe Feb 08 '18 at 10:21
  • @CBroe $connection->query('SELECT 1;'); – Sergei Kasatkin Feb 08 '18 at 10:25
  • 1
    Perhaps it's only an overlook. The C codebase needs to support three error handling modes and I presume that needs to be coded explicitly everywhere. There're surely edge cases like this that aren't fully covered. – Álvaro González Feb 08 '18 at 10:26
  • Ah, you said already, sorry, overlooked that. Just wanted to be sure it was not perhaps any of the other calls, outside try/catch, that might perhaps throw the warnings. – CBroe Feb 08 '18 at 10:26

2 Answers2

4

I'd dare say it's a bug. I found two relevant tickets:

  • Bug #63812: PDO Triggers Warning(s) Regardless of Error Handling Strategy, filed on 2012 for PHP/5.3.19
  • Bug #74401: PDO trigger warning already set throw exception, filed on 2017 for PHP/7.0.17

In any case, they're still open and it isn't entirely clear whether they're valid issues (though I suspect they are). It doesn't seem to be a design decision because other MySQL errors do not trigger both, warning and exception:

$connection = new PDO('mysql:host=127.0.0.1;dbname=test', 'test', 'test',
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING]);
$connection->query('SELECT * FROM foo');

Warning: PDO::query(): SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.foo' doesn't exist

$connection = new PDO('mysql:host=127.0.0.1;dbname=test', 'test', 'test',
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$connection->query('SELECT * FROM foo');

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.foo' doesn't exist'

Álvaro González
  • 142,137
  • 41
  • 261
  • 360
0

The purpose of PDO::ERRMODE_EXCEPTION is not to prevent php warnings, notices or similar things.
As you can read in the documentation you have already provided by yourself it will raise an exception instead of writing a mysql error silently into the result.
So instead of you manually checking if the result has an error (mysql has gone away, you have a syntax error..., etc.) on the result, PDO will directly throw an exception which you can catch.
And PDO::ERRMODE_EXCEPTION does exactly that as your code proves.
You have to differ between php errors, warnings etc which will still be shown and mysql errors which will be converted into an exception instead of being saved in the result.

Eydamos
  • 562
  • 4
  • 16