Skip to main content

❌ 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 of strlen())
  • Function defined in a file that hasn't been included
  • Missing PHP extension (e.g., json_encode needs 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

  1. Are Apache and MySQL running? (sudo service apache2 status / sudo service mysql status)
  2. Did you save the file? (Check the file's modification timestamp)
  3. Are you editing the right file? (The one Apache is serving, not a copy somewhere else)
  4. Is your browser caching the old page? (Hard refresh: Ctrl+Shift+R)
  5. Did you recently change php.ini? (Restart Apache: sudo service apache2 restart)