PDO不抛出异常求助:已设ERRMODE_EXCEPTION仍无法捕获异常
Hey there, let's work through why your PDO exceptions aren't firing even after setting PDO::ATTR_ERRMODE to PDO::ERRMODE_EXCEPTION. This is a common gotcha, especially with frameworks like Slim that have their own error handling layers. Let's break down possible causes and fixes step by step:
1. Verify Your PDO Instance's Error Mode is Actually Set
First, make sure the PDO instance you're using in your insert code has the error mode properly configured. Sometimes in frameworks, you might accidentally use a different PDO instance than the one you initialized with the correct settings.
Add this check right after you set the attributes on your PDO instance:
var_dump($pdo->getAttribute(PDO::ATTR_ERRMODE)); // Expected output: int(2) (since PDO::ERRMODE_EXCEPTION = 2)
If this doesn't return int(2), your attribute setting is failing. Double-check that you're not reinitializing PDO elsewhere in your code without setting the error mode.
2. Test PDO Exceptions Outside the Framework
To rule out Slim's interference, create a standalone test script that uses your database credentials and tries to insert duplicate data directly:
<?php $db = [ 'host' => 'your_host', 'dbname' => 'your_db', 'user' => 'your_user', 'pass' => 'your_pass' ]; $testPdo = new PDO("mysql:host=" . $db['host'] . ";dbname=" . $db['dbname'], $db['user'], $db['pass']); $testPdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); try { // Replace with your table and a value that violates the unique constraint $testPdo->exec("INSERT INTO your_table (unique_column) VALUES ('duplicate_value')"); echo "No exception thrown - check if the value is actually duplicate!"; } catch (PDOException $e) { echo "Exception caught successfully: " . $e->getMessage(); } ?>
If this script catches the exception, the problem is in how your Slim app handles the PDO instance or errors. If it doesn't, double-check your database's unique constraint (is it applied to the right column?) or if the data you're inserting is truly duplicate (watch for whitespace or case sensitivity!).
3. Check Slim 3's Error Handling Middleware
Slim 3 has a built-in error middleware that manages unhandled exceptions, but your try/catch should still catch exceptions inside the wrapped block. That said, custom error handlers might interfere.
Check if you've enabled the default error middleware in your Slim setup:
$app = new Slim\App(); // Default error middleware $app->addErrorMiddleware(true, true, true);
Even with this enabled, your try/catch should catch exceptions from execute(). But if you've added a custom error handler that swallows or rethrows exceptions, try temporarily disabling it to test.
4. Validate Your SQL and Parameter Binding
Looking at your insert code, make sure your prepared statements and parameter binding work as expected:
- Print the generated
$sqlto confirm placeholders match the keys you're binding:var_dump($sql); // Should look like: INSERT INTO table (col1, col2) VALUES (:col1, :col2) - Ensure every placeholder in
$valueStringhas a corresponding key in$request_data—if a placeholder is missing,execute()should throw an exception, but if you're accidentally concatenating values directly into$valueStringinstead of using placeholders, you might not trigger the error you expect.
5. Ensure Proper PDI Injection in Slim
In Slim 3, use the dependency container to manage your PDO instance, so you don't accidentally create multiple instances with different configurations. Here's how to set it up:
$container = $app->getContainer(); $container['pdo'] = function ($c) { $dbSettings = $c['settings']['db']; $pdo = new PDO( "mysql:host={$dbSettings['host']};dbname={$dbSettings['dbname']}", $dbSettings['user'], $dbSettings['pass'] ); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); return $pdo; };
Then access it in your controller via $this->pdo—this guarantees you're always using the same PDO instance with the correct error mode.
Final Checks
- Confirm your database table has the unique constraint applied: Run
SHOW INDEX FROM your_table;in your database client to verify the unique index exists on the correct column(s). - Check for case sensitivity: Some MySQL collations are case-insensitive, but if you're using a case-sensitive one,
'test'and'Test'won't be considered duplicates.
内容的提问来源于stack exchange,提问作者Martin

