Avatar of elepil
elepil
 asked on

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?
PHPMySQL Server

Avatar of undefined
Last Comment
Ray Paseur

8/22/2022 - Mon
ASKER CERTIFIED SOLUTION
Chris Stanyon

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
Chris Stanyon

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.
elepil

ASKER
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().
Chris Stanyon

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

All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
elepil

ASKER
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 Paseur

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