Fix the fetchAll(PDO::FETCH_ASSOC) Error in PHP

The way I’ve been handling errors in my PHP code works, but I have to admit, it’s becoming really tedious. Let me explain. Suppose I need to call a function in the middle of my code, check a variable’s value, or ensure a database query returned a valid result. When something fails, I end up writing another if/else block, pushing all the code inside that new block. It gets messy and cumbersome pretty quickly.

I’ve been reading about try/catch and it seems like a cleaner solution. Instead of constantly creating if/else blocks, I could wrap everything inside a try block, and if something fails, I could throw an exception. That way, the code jumps straight to the catch block, much like how an else block would work after a failed if statement. It seems like a more efficient approach, but I’m still unsure whether this is considered a standard practice for handling errors.

Here’s what I’m trying to figure out: What’s the best way to handle both fatal and non-fatal errors in a PHP application? My goal is to avoid blank screens (which are terrible for user experience) and instead show meaningful error messages, while still allowing the page header and footer to display.

PHP Code (with Errors):

codeif($_GET['something'] == 'somevalue') 
{
$output .= 'somecode';

// make a DB query, fetch a row
$row = $stmt->Fetch(PDO::ASSOC);

if($row != null)
{
$output .= 'morecode';

if(somethingIsOK())
{
$output .= 'yet more page output';
}
else
{
$error = 'something is most definitely not OK.';
}
}
else
{
$error = 'the row does not exist.';
}
}
else
{
$error = 'something is not a valid value';
}

if($error == '') // no error
{
// display $output on page
}
else // an error
{
// display whatever error occurred on the page
}

Issues:

  1. Repetitive if/else blocks: Every time I check for a condition, like whether the database query returns a valid result or whether the value is okay, I have to create a new if/else block. It’s tedious and clutters the code.
  2. Manual error handling: Instead of automating error handling, I’m manually checking and displaying errors, which leads to extra work and repetitive code.

Corrected PHP Code:

codeif (isset($_GET['something']) && $_GET['something'] === 'somevalue') {
$output = ''; // Initialize $output to prevent undefined variable issues
$error = ''; // Initialize $error variable

$output .= 'somecode';

// Simulate a DB query, using try/catch for error handling
try {
// Assuming $stmt is a valid PDO statement object
$stmt = $pdo->prepare("SELECT * FROM your_table WHERE condition = :condition");
$stmt->execute(['condition' => 'some_condition']);
$row = $stmt->fetch(PDO::FETCH_ASSOC);

if ($row !== false) {
$output .= 'morecode';

if (somethingIsOK()) {
$output .= 'yet more page output';
} else {
$error = 'Something is most definitely not OK.';
}
} else {
$error = 'The row does not exist.';
}
} catch (Exception $e) {
$error = 'Database query failed: ' . $e->getMessage();
}
} else {
$error = 'Something is not a valid value.';
}

// Output the results based on whether an error occurred
if (empty($error)) {
// Display $output on the page
echo $output;
} else {
// Display the error on the page
echo "<p>Error: $error</p>";
}

Key Improvements

  1. Validation of $_GET['something']:
    • We added isset($_GET['something']) to check if the value exists before comparing it. This prevents potential warnings if the parameter isn’t set in the URL.
  2. Initialization of Variables:
    • Both $output and $error are initialized at the start of the block to avoid potential “undefined variable” errors.
  3. Database Query Using PDO:
    • I replaced the placeholder query with a PDO prepare() and execute() call. This uses prepared statements to prevent SQL injection. The fetch() method with PDO::FETCH_ASSOC safely fetches data from the database.
  4. Error Handling with try/catch:
    • The database query is wrapped in a try/catch block to handle any exceptions that might occur (e.g., failed queries). This ensures that any issues are caught, and the user is shown a helpful error message instead of a blank screen.
  5. Using empty() for Error Checking:
    • Instead of checking if $error == '', the code now uses empty($error) to check if any error occurred. This approach is more robust and avoids issues with null or falsy values.

Conclusion

By restructuring the code, we’ve made it more secure, readable, and easier to maintain. Error handling is improved with try/catch blocks, the database queries are protected against SQL injection with prepared statements, and the input validation ensures no warnings are raised for missing $_GET parameters.

Related blog posts