Errors and debugging
Besides the exceptions your code throws, PHP itself reports problems: reading a variable that does not exist, dividing by zero, a typo in a function name. Being able to read these messages saves hours of bug hunting.
Kinds of messages
| Kind | What it means | The program continues |
|---|---|---|
| Notice, Deprecated | A remark: a possible inaccuracy, an outdated feature | Yes |
| Warning | Something went wrong | Yes |
| Fatal error | A fatal error | No |
| Parse error | A syntax error in the code | It does not start |
A warning does not stop the program, but it almost always means a logic error. It must not be ignored.
Reading a message
A message names the cause, the file and the line number:
Warning: Undefined variable $total in /var/www/cart.php on line 12Start with the line given. If it looks fine, look above it: the cause is often a few lines earlier.
Displaying errors
During development errors are shown on screen; on a live site they are written to a log. Settings control this:
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
echo 'All errors are shown';On a production server display_errors is turned off: an error message reveals file paths and code details to the visitor.
The error log
The error_log() function writes a message to the server log. The user does not see it:
<?php
function divide(int $a, int $b): ?float
{
if ($b === 0) {
error_log('Attempt to divide by zero');
return null;
}
return $a / $b;
}
echo divide(10, 4); // 2.5Warnings as exceptions
A warning cannot be caught with try. The set_error_handler() function lets you turn it into an exception — and handle every problem in one way:
<?php
set_error_handler(function (int $level, string $message) {
throw new ErrorException($message);
});
try {
echo $undefined;
} catch (ErrorException $error) {
echo 'Caught: ', $error->getMessage();
}Frameworks do exactly this: any notice stops execution and ends up in the common handler.
Debugging
To see what a variable holds, print it with var_dump() — it shows both the type and the value:
<?php
$user = ['name' => 'Anna', 'age' => 25, 'active' => true];
var_dump($user['age']);
echo json_encode($user);For large arrays print_r() or json_encode() is handier. Serious projects use the Xdebug debugger: it stops the program at a chosen line and shows every variable.
A global exception handler
set_exception_handler() sets a function that receives any uncaught exception. It shows the visitor a polite page and writes the details to the log:
<?php
set_exception_handler(function (Throwable $error) {
echo 'Something went wrong. We are already looking into it.';
});
throw new RuntimeException('The database is unavailable');Common mistake
The @ operator before an expression suppresses the error message. The problem does not go away — you just stop seeing it:
<?php
$config = ['theme' => 'dark'];
// Bad: $size = @$config['size'];
$size = $config['size'] ?? 14;
echo $size; // 14Instead of suppressing, check the data: the ?? operator, isset(), file_exists().