PHP PDO question on how to use try/catch block

I just learned that PDO and mysqli both do NOT throw exceptions by default. I learned that to make mysqli throw exceptions, one has to have this line of code:

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

Open in new window


and in PDO, one has to have this line of code:

$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Open in new window


There is one very significant difference between the two. In mysqli, that line of code is done BEFORE obtaining a database connection. In PDO, that line of code is done AFTER obtaining a database connection. In fact, PDO requires an already successful database connection before one can even tell it to throw exceptions.

So here is my question. In PDO, how can I use the try/catch block to catch an incorrect user/password combination or incorrect database name while connecting to the database, an error condition that happens BEFORE having obtained a database connection?
elepilAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Chris StanyonWebDevCommented:
Try it :)

You'll get the exception thrown exactly as you expect:

try {
	$dbh = new PDO('mysql:host=localhost;dbname=someDB', 'username', 'wrongPassword');
	$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
} catch(PDOException $e) {
	die($e->getMessage());
}

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Chris StanyonWebDevCommented:
Oops - forget to explain why :)

The PDO::ATTR_ERRMODE tells PDO how to handle errors on the database connection.

The PDO constructor (new PDO(...) ) throws a PDOException when there's a problem. The setAttribute() method doesn't effect that at all.
elepilAuthor Commented:
Chris, your code snippet demonstrates exactly what I did originally and it didn't work. Notice you did your $dbh->setAttribute() AFTER the creation of the PDO object. To use the setAttribute method, you needed to have a valid PDO reference in $dbh to begin. But if the user/password is wrong, at that point, PDO doesn't know YET it was supposed to throw an exception because the line that tells it to do so is the next line.

This is what I get when my code tries to execute the $dbh->setAttribute() method:

Fatal error: Call to a member function setAttribute() on a non-object in C:\xampp\htdocs\newdimension\public\ndLogin.php on line 9

It's complaining that $dbh is a "non-object", and hence, does not have a member function called setAttribute().
Protecting & Securing Your Critical Data

Considering 93 percent of companies file for bankruptcy within 12 months of a disaster that blocked access to their data for 10 days or more, planning for the worst is just smart business. Learn how Acronis Backup integrates security at every stage

Chris StanyonWebDevCommented:
I think you're confusing 2 different error handling routines. The constructor of PDO will throw an exception if something is wrong. That has nothing to do with setting the ATTR_ERRMODE attribute. It's just the normal way the constructor works - if it fails, it throws an exception!

This is why you should always wrap the PDO constructor in a try/catch block. If the constructor fails, you can catch the exception. In the code I posted, if there was a problem with creating the connection, such as a bad username or password, then a PDOException would be thrown - the code would jump into the catch block and the setAttribute line would never be executed.

Maybe this code will make things clearer:

try {
	$dbh = new PDO('mysql:host=localhost;dbname=someDB', 'username', 'wrongPassword');
} catch (PDOException $e) {
	// There was a problem creating the connection so lets kill the script with some feedback to the user
	die($e->getMessage());
}

// If we get here then we know that $dbh has been created successfully
// We can now explicitly set how database errors are handled for this connection
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

Open in new window

elepilAuthor Commented:
Oh sorry, Chris, my mistake. You're right. It was working on my side, just didn't do the code right to display the catch error message properly. The new PDO() was throwing an exception. Thanks for your help.
Ray PaseurCommented:
Maybe this will help.  Step through the code and watch it in action.
http://iconoun.com/demo/temp_elepil.php

<?php // demo/temp_elepil.php
ini_set('display_errors', TRUE);
error_reporting(E_ALL);
echo '<pre>';

// THE ABSOLUTE MINIMUM YOU MUST UNDERSTAND TO USE PHP AND PDO/MYSQL
// MAN PAGE: http://php.net/manual/en/book.pdo.php
// MAN PAGE: http://php.net/manual/en/class.pdo.php
// MAN PAGE: http://php.net/manual/en/class.pdoexception.php
// MAN PAGE: http://php.net/manual/en/class.pdostatement.php
// MAN PAGE: http://php.net/manual/en/pdo.construct.php
// MAN PAGE: http://php.net/manual/en/pdo.setattribute.php
// MAN PAGE: http://php.net/manual/en/pdo.query.php
// MAN PAGE: http://php.net/manual/en/pdo.prepare.php
// MAN PAGE: http://php.net/manual/en/pdo.prepare.php#97942 <-- NO CURSOR SCROLLING
// MAN PAGE: http://php.net/manual/en/pdostatement.execute.php
// MAN PAGE: http://php.net/manual/en/pdo.lastinsertid.php
// MAN PAGE: http://php.net/manual/en/pdostatement.bindparam.php
// MAN PAGE: http://php.net/manual/en/pdostatement.rowcount.php
// MAN PAGE: http://php.net/manual/en/pdostatement.fetchall.php
// MAN PAGE: http://php.net/manual/en/pdostatement.fetchobject.php


// DATABASE CONNECTION AND SELECTION VARIABLES ARE INCOMPLETE HERE
$db_host = "localhost";
$db_name = "foo";
$db_user = "bar";
$db_word = "baz";


// WARNING: AN UNCAUGHT CONNECT ERROR WILL BARK OUT THE DB CREDENTIALS!
// $pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, 'foo');

echo '<h1>FAILURE</h1>';
// OPEN A CONNECTION TO THE DATA BASE SERVER AND SELECT THE DB
$dsn = "mysql:host=$db_host;dbname=$db_name";
try
{
    $pdo = new PDO($dsn, $db_user, $db_word);
}
catch(PDOException $exc)
{
    var_dump($exc);
    trigger_error($exc->getMessage(), E_USER_WARNING);
}

// SHOW THE (FAILED) PDO CONNECTION OBJECT
var_dump($pdo);
echo PHP_EOL;


// NOW TRY IT AGAIN WITH THE RIGHT CREDENTIALS
require_once('RAY_live_data.php');

echo '<h1>SUCCESS</h1>';
// OPEN A CONNECTION TO THE DATA BASE SERVER AND SELECT THE DB
$dsn = "mysql:host=$db_host;dbname=$db_name";
try
{
    $pdo = new PDO($dsn, $db_user, $db_word);
}
catch(PDOException $exc)
{
    var_dump($exc);
    trigger_error($exc->getMessage(), E_USER_WARNING);
}

// SHOW THE (HAPPY) PDO CONNECTION OBJECT (ENTIRELY EMPTY!)
var_dump($pdo);
echo PHP_EOL;

Open in new window

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.