Every developer spends a large part of their time fixing things that do not work. The difference between beginners and experienced developers is not fewer errors, it is reading them calmly and finding the cause quickly.
Reading an error message
PHP Warning: Undefined array key "email" in /var/www/public/contact.php on line 14
Every message tells you three things:
- The level: Warning, Fatal error, Parse error, Deprecated.
- What went wrong: here, reading a key that does not exist.
- Where: the file and line number.
Go to that line first. For parse errors, also check the line before, as you saw in the syntax lesson.
Error levels
| Level | Example cause | Script continues? |
|---|---|---|
| Parse error | Missing semicolon or bracket | No, nothing runs |
| Fatal error | Calling an undefined function | No |
| Warning | Undefined variable or array key | Yes, but results may be wrong |
| Deprecated | Using a feature that will be removed | Yes |
Do not ignore warnings because the page "still works". A warning almost always means a value is not what you think it is, and that becomes a real bug later.
Showing errors in development, hiding them in production
While developing you want to see every error. In production, visitors must never see them: messages reveal file paths and details that help attackers.
Development (php.ini or at the top of a script while learning):
<?php
ini_set('display_errors', '1');
error_reporting(E_ALL);
Production php.ini:
display_errors = Off
log_errors = On
error_log = /var/log/php/error.log
error_reporting = E_ALL
Errors are still recorded, just in a log file instead of the page. Run php --ini to find which php.ini your installation uses.
Exceptions
Many failures in modern PHP are exceptions: objects that are thrown when something goes wrong and can be caught and handled.
<?php
declare(strict_types=1);
function divide(int $a, int $b): float
{
if ($b === 0) {
throw new InvalidArgumentException('Cannot divide by zero.');
}
return $a / $b;
}
try {
echo divide(10, 2), PHP_EOL; // 5
echo divide(10, 0), PHP_EOL; // throws
echo 'Never reached';
} catch (InvalidArgumentException $e) {
echo 'Error: ', $e->getMessage(), PHP_EOL;
} finally {
echo 'Done.', PHP_EOL;
}
5
Error: Cannot divide by zero.
Done.
throwstops the function immediately.trywraps code that might fail;catchhandles a specific exception type.finallyalways runs, which is useful for clean-up such as closing files.
You can catch several types, and Throwable catches everything, including engine errors like TypeError:
<?php
try {
$result = intdiv(10, 0);
} catch (DivisionByZeroError | TypeError $e) {
error_log($e->getMessage());
echo 'Something went wrong with that calculation.';
}
Only catch an exception where you can do something useful: show a friendly message, retry, or use a fallback. An empty catch block hides bugs and makes them much harder to find.
A debugging method that works
When something is wrong and the message does not make the cause obvious:
- Reproduce it reliably. Find the exact input and steps that trigger the problem.
- Read the full message and go to the reported line.
- Check your assumptions. Print the values you are relying on:
<?php
var_dump($user); // Shows the type and value
exit; // Stop here so the output is easy to find
- Halve the search space. Put a check in the middle of the code path. Is the value already wrong there? Then the bug is earlier; otherwise it is later.
- Change one thing at a time and re-run.
- Explain the problem out loud, even to nobody. Describing it step by step often reveals the wrong assumption.
Logging instead of printing
On a live site, or inside code that produces JSON or redirects, printing breaks the output. Write to the error log instead:
<?php
error_log('Checkout total: ' . print_r($cart, true));
Using a debugger
Xdebug lets you pause code at a breakpoint, inspect every variable and step through line by line in VS Code or PhpStorm. It takes a few minutes to set up and repays that time on the first serious bug. Install it once you are comfortable with the basics.
Common beginner errors and fixes
| Message | Usual cause | Fix |
|---|---|---|
| Parse error: unexpected token | Missing ;, ) or } | Check the reported line and the one before |
| Undefined variable | Typo, or variable defined in another scope | Check spelling; pass it into the function |
| Undefined array key | Reading optional input | Use $array['key'] ?? default |
| Call to undefined function | Typo, or file not included | Check spelling and require_once |
| Cannot redeclare function | File included twice | Use require_once |
| Headers already sent | Output before header() | Remove whitespace before <?php; omit ?> |
Summary
- Read the level, message, file and line; parse errors may start one line earlier.
- Show errors while developing; log them, never display them, in production.
- Use exceptions with
try,catchandfinally; catch only what you can handle. - Debug methodically: reproduce, check assumptions with
var_dump, halve the search space. - Log with
error_log()on live sites, and try Xdebug when you are ready.
You finished the course
You can now write PHP scripts, handle data with arrays and functions, process forms safely and fix errors with confidence. Take the final quiz to check your understanding, then continue with Object-Oriented PHP or PHP and MySQL.