Introduction: Why Error Handling is the Foundation of Reliable PHP Code
Every PHP developer encounters errors. Whether it's invalid user input, an unavailable database, or an unexpected API failure — without proper error handling, an application turns into a fragile structure that can "crash" at any moment. Error handling in PHP is not just a way to avoid the White Screen of Death (WSOD), but a fundamental principle for creating stable, secure, and maintainable web applications.
In this article, we will break down all aspects of error handling in PHP: from the basic try/catch mechanism to creating custom exceptions and advanced logging strategies. You will learn how to turn the chaos of errors into a manageable and predictable process.
Basics: try, catch, finally, and throw
The try/catch Block — The First Line of Defense
The exception mechanism in PHP is based on the try/catch construct. Code that might cause an error is placed inside the try block. If an exception occurs within it, execution immediately moves to the catch block, where the error is handled.
<?phptry { $file = fopen('important_data.txt', 'r'); if (!$file) { throw new Exception('Failed to open file'); } // Work with the file fclose($file);} catch (Exception $e) { echo 'Error: ' . $e->getMessage();}?>It is important to understand: not all errors in PHP are exceptions. Standard warnings and notices do not generate exceptions automatically. Catching them requires special configuration (see the "Advanced Techniques" section).
The finally Block — Guaranteed Execution
The finally block always executes, regardless of whether an exception was thrown or not. This is the ideal place to release resources: closing files, database connections, or freeing memory.
<?phpfunction processData($data) { $connection = null; try { $connection = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass'); // Execute queries return $connection->query($data); } catch (PDOException $e) { // Log the error error_log('DB Error: ' . $e->getMessage()); return false; } finally { // Close the connection in any case if ($connection) { $connection = null; } }}?>The throw Statement — Creating Your Own Exceptions
Using throw, you can generate exceptions at any point in your code. This allows you to create clear and predictable error scenarios.
<?phpfunction validateAge($age) { if (!is_numeric($age)) { throw new InvalidArgumentException('Age must be a number'); } if ($age < 0 || $age > 150) { throw new OutOfRangeException('Age is outside the valid range'); } return true;}
try { validateAge('abc');} catch (InvalidArgumentException $e) { echo 'Validation error: ' . $e->getMessage();} catch (OutOfRangeException $e) { echo 'Invalid range: ' . $e->getMessage();}?>Custom Exception Classes
Standard exception classes (Exception, RuntimeException, InvalidArgumentException) cover many scenarios, but for complex projects, it is better to create your own exception hierarchies. This improves code readability and simplifies debugging.
Creating a Custom Exception Class
<?phpclass DatabaseException extends Exception { private $queryString; public function __construct($message, $query = '', $code = 0, Throwable $previous = null) { $this->queryString = $query; parent::__construct($m