❌ Common PHP Errors
A reference guide to the most frequently encountered PHP errors, what causes them, and how to fix them. When you hit an error, search this page for the error message.
📑 Sections
Parse (Syntax) Errors
Parse errors mean PHP can't even read your code — it's structurally broken. The script won't run at all.
Parse error: syntax error, unexpected token "..."
What it means: PHP found something it wasn't expecting at that position.
Common Causes & Fixes:
// 1. Missing semicolon — error usually points to NEXT line
$name = "Ray" // ← Missing ;
echo $name; // ← Error reported HERE
// Fix:
$name = "Ray";
// 2. Unclosed string
echo "Hello world; // Missing closing quote
// 3. Unclosed parenthesis or bracket
if ($x > 5 { // Missing )
echo "big";
}
// 4. Extra closing brace
function test() {
echo "hello";
}} // ← Extra }
// 5. Using PHP 8 syntax on PHP 7
$result = match($x) { ... }; // match requires PHP 8.0+
💡 Pro Tip
The error line number often points to where PHP noticed the problem, not where the actual mistake is. Check the line before the reported line first.
Parse error: syntax error, unexpected end of file
What it means: PHP reached the end of the file but expected more code (something is unclosed).
// Usually means: unclosed { } or missing <?php / ?>
function greet($name) {
if ($name) {
echo "Hello, $name!";
// ← Missing closing } for the function
// Fix: count your opening and closing braces
// Tip: Use an editor with brace matching
Fatal Errors
Fatal errors stop script execution immediately.
Fatal error: Uncaught Error: Call to undefined function foo()
Common Causes:
- Typo in the function name (
streln()instead ofstrlen()) - Function defined in a file that hasn't been included
- Missing PHP extension (e.g.,
json_encodeneeds the JSON extension)
// Check spelling carefully
// strlen() not streln()
// Make sure the file is included
require_once __DIR__ . '/functions.php';
// Check if a function exists before calling
if (function_exists('my_function')) {
my_function();
}
Fatal error: Uncaught Error: Class "ClassName" not found
Common Causes:
- Class file not included/required
- Typo in the class name (case-sensitive!)
- Namespace not imported
// Include the class file
require_once __DIR__ . '/classes/User.php';
// Or if using namespaces:
use App\Models\User;
// Check your spelling — class names are case-insensitive
// but it's best practice to match the exact case
Fatal error: Cannot redeclare function/class
Cause: The same function or class is defined twice (usually from including a file twice).
// Bad — file gets included multiple times
include 'functions.php'; // Page A includes it
include 'functions.php'; // Page A includes it again via another file
// Fix — use require_once or include_once
require_once __DIR__ . '/functions.php';
Fatal error: Allowed memory size of X bytes exhausted
Cause: Script consumed more memory than the limit (usually 128 MB).
// Quick fix — increase the limit
ini_set('memory_limit', '256M');
// Better fix — find the cause:
// - Infinite loop
// - Loading a massive file into memory
// - Fetching millions of database rows at once
// - Recursive function without a base case
// Process large datasets in chunks:
$stmt = $pdo->query("SELECT * FROM huge_table");
while ($row = $stmt->fetch()) {
// Process one row at a time instead of fetchAll()
}
Fatal error: Maximum execution time of 30 seconds exceeded
Cause: Script ran longer than max_execution_time (default 30s).
// Increase the limit (for specific scripts)
set_time_limit(120); // 120 seconds
// Or in php.ini:
// max_execution_time = 120
// Better: figure out WHY it's slow
// - Slow database query? Add indexes
// - Infinite loop? Check loop conditions
// - External API timeout? Set a timeout
Warnings
Warnings don't stop execution but indicate something is likely wrong.
Warning: Undefined variable $varname
Cause: Using a variable that hasn't been assigned a value.
// Bad
echo $username; // $username was never set
// Fix 1: Initialize the variable
$username = '';
// Fix 2: Use null coalescing for optional data
$username = $_POST['username'] ?? '';
// Fix 3: Check with isset()
if (isset($username)) {
echo $username;
}
Warning: Undefined array key "keyname"
Cause: Accessing an array key that doesn't exist.
// Bad — 'email' key might not exist
echo $_POST['email'];
// Fix: use null coalescing
$email = $_POST['email'] ?? '';
// Or check first
if (isset($_POST['email'])) {
$email = $_POST['email'];
}
// Or use array_key_exists()
if (array_key_exists('email', $_POST)) { ... }
Warning: foreach() argument must be of type array|object, null given
Cause: The variable you're iterating over is null instead of an array.
// Bad
$items = null;
foreach ($items as $item) { ... } // Warning!
// Fix: provide a default empty array
$items = getItems() ?? [];
foreach ($items as $item) { ... }
// Or check first
if (!empty($items)) {
foreach ($items as $item) { ... }
}
Warning: Division by zero
// Bad
$average = $total / $count; // Crashes if $count is 0
// Fix: check before dividing
$average = ($count > 0) ? $total / $count : 0;
Warning: Cannot modify header information — headers already sent
Cause: Output was sent to the browser before calling header(), session_start(), or setcookie().
// The error message tells you WHERE output started:
// "headers already sent by (output started at /var/www/html/page.php:5)"
// Check line 5 of page.php for:
// - echo or print statements
// - HTML before <?php
// - Whitespace or blank lines before <?php
// - A BOM (byte order mark) — save file as UTF-8 without BOM
// Fix: put all header/session/cookie calls BEFORE any output
<?php
session_start(); // ← First
header("Location: /home"); // ← Before any HTML
exit;
?>
Notices & Deprecations
Less severe, but you should still fix them.
Deprecated: Function name() is deprecated
Cause: You're using a function that will be removed in a future PHP version.
// Common deprecated functions and their replacements:
// mysql_connect → use PDO instead (mysql_* removed in PHP 7)
// each() → use foreach instead (deprecated in PHP 7.2)
// create_function() → use anonymous functions (deprecated in PHP 7.2)
// utf8_encode/decode → use mb_convert_encoding (deprecated in PHP 8.2)
// Old:
$encoded = utf8_encode($string);
// New:
$encoded = mb_convert_encoding($string, 'UTF-8', 'ISO-8859-1');
Notice: Array to string conversion
Cause: Trying to use an array where a string is expected.
// Bad
$colors = ["red", "green", "blue"];
echo $colors; // Notice: Array to string conversion → prints "Array"
// Fix: use implode() or print_r()
echo implode(", ", $colors); // "red, green, blue"
print_r($colors); // Array ( [0] => red ... )
PDO & Database Errors
PDOException: could not find driver
Cause: The PDO MySQL extension isn't installed.
sudo apt install php-mysql
sudo service apache2 restart
# Verify: php -m | grep pdo
PDOException: SQLSTATE[HY000] [2002] Connection refused
Cause: MySQL isn't running or the host/port is wrong.
# Check if MySQL is running
sudo service mysql status
# Start it if needed
sudo service mysql start
# Verify your DSN uses the correct host:
# "mysql:host=localhost" or "mysql:host=127.0.0.1"
PDOException: SQLSTATE[HY000] [1045] Access denied for user
Cause: Wrong username, password, or user lacks database access.
// 1. Verify credentials work from command line:
// mysql -u your_user -p
// 2. Check the user exists and has access:
// sudo mysql
// SELECT User, Host FROM mysql.user;
// SHOW GRANTS FOR 'your_user'@'localhost';
// 3. Double-check your PHP connection:
$pdo = new PDO(
"mysql:host=localhost;dbname=your_db;charset=utf8mb4",
"your_user", // ← correct?
"your_password", // ← correct?
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
PDOException: SQLSTATE[42S02] Table 'db.table' doesn't exist
Cause: The table name is wrong or the database doesn't contain that table.
// Check your table name (case-sensitive on Linux!)
// In MySQL: SHOW TABLES;
// Common mistake: connecting to the wrong database
// Check your DSN: dbname=correct_database
PDOException: SQLSTATE[HY093] Invalid parameter number
Cause: Mismatch between placeholders and values.
// Bad — 2 placeholders, 3 values
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->execute([$name, $email, $age]); // 3 values!
// Fix: match the count
$stmt->execute([$name, $email]);
// With named placeholders, keys must match exactly:
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(['id' => $userId]); // 'id' matches ':id'
File & Permission Errors
Warning: file_get_contents(): Failed to open stream: No such file or directory
// Check: does the file exist?
if (file_exists('data.txt')) {
$content = file_get_contents('data.txt');
}
// Use __DIR__ for reliable paths:
$content = file_get_contents(__DIR__ . '/data/file.txt');
// Remember: paths are relative to the EXECUTING script
Warning: file_put_contents(): Failed to open stream: Permission denied
# Apache runs as www-data — give it write permission
sudo chown www-data:www-data /var/www/html/data/
sudo chmod 755 /var/www/html/data/
Warning: require(): Failed opening required 'file.php'
Cause: require can't find the file — fatal error, script stops.
// Use absolute paths with __DIR__
require __DIR__ . '/includes/config.php';
// If the file is optional, use include instead:
include __DIR__ . '/includes/optional.php'; // Warning only, script continues
Session & Header Errors
Warning: session_start(): Session cannot be started after headers have already been sent
Fix: Move session_start() to the very first line of your script, before any output.
<?php
session_start(); // Must be FIRST — before any HTML, whitespace, or echo
?>
<!DOCTYPE html>
...
Session data disappears between pages
Checklist:
session_start()is called at the top of every page that reads$_SESSION- You're not accidentally calling
session_destroy() - URLs are consistent (not mixing
localhost/127.0.0.1/ IP address) - Browser cookies aren't disabled
OOP Errors
Fatal error: Using $this when not in object context
Cause: Using $this in a static method, or calling an instance method statically.
class User {
public string $name;
public static function create(): self {
// $this->name = "Ray"; // WRONG — no $this in static methods
$user = new self(); // Create an instance instead
$user->name = "Ray";
return $user;
}
}
// Also wrong: calling an instance method statically
// User::greet(); // If greet() uses $this, this fails
Fatal error: Cannot access private property
class Account {
private float $balance = 0;
public function getBalance(): float {
return $this->balance;
}
}
$account = new Account();
// echo $account->balance; // FATAL — private!
echo $account->getBalance(); // Correct
Fatal error: Class must implement all abstract methods
abstract class Shape {
abstract public function area(): float;
abstract public function perimeter(): float;
}
class Circle extends Shape {
public function area(): float { return M_PI * $this->r ** 2; }
// FATAL — missing perimeter() implementation!
public function perimeter(): float { return 2 * M_PI * $this->r; }
// Fix: implement ALL abstract methods
}
General Debugging Tips
🔹 Step 1: Make Errors Visible
// Add to the top of your script during development:
error_reporting(E_ALL);
ini_set('display_errors', 1);
// For production, log errors instead of displaying them:
ini_set('display_errors', 0);
ini_set('log_errors', 1);
// Check: sudo tail -f /var/log/apache2/error.log
🔹 Step 2: Use var_dump() Strategically
// Dump and die — quick debug, then stop
var_dump($variable); die();
// Pretty-print arrays
echo "<pre>";
var_dump($data);
echo "</pre>";
// Check what a form actually sent
echo "<pre>";
var_dump($_POST);
echo "</pre>";
🔹 Step 3: Read the Error Message
PHP error messages contain everything you need:
- Error type — Parse error, Fatal error, Warning, Notice
- Description — what went wrong
- File path — which file contains the error
- Line number — where PHP noticed the problem (check the line before too)
🔹 Step 4: Check the Apache Error Log
# View the most recent errors
sudo tail -30 /var/log/apache2/error.log
# Watch errors in real-time (leave this running in a terminal)
sudo tail -f /var/log/apache2/error.log
🔹 The "It Was Working Yesterday" Checklist
- Are Apache and MySQL running? (
sudo service apache2 status/sudo service mysql status) - Did you save the file? (Check the file's modification timestamp)
- Are you editing the right file? (The one Apache is serving, not a copy somewhere else)
- Is your browser caching the old page? (Hard refresh: Ctrl+Shift+R)
- Did you recently change php.ini? (Restart Apache:
sudo service apache2 restart)