Skip to main content
  1. Languages/
  2. PHP Guides/

Top Common PHP Errors and How to Fix Them Instantly

Jeff Taakey
Author
Jeff Taakey
21+ Year CTO & Multi-Cloud Architect.

Even in the modern landscape of 2025, where frameworks like Laravel and Symfony handle much of the heavy lifting, raw PHP errors can still bring a production application to a screeching halt. Whether you are maintaining a legacy codebase or building high-performance microservices, encountering the “White Screen of Death” or cryptic log messages is an inevitable part of the job.

The difference between a junior developer and a senior engineer isn’t that the senior never makes mistakes—it’s that the senior knows exactly how to interpret the error message and fix it in seconds.

In this guide, we will dissect the most common PHP errors that developers face today. We will look at why they happen, how to fix them using modern PHP 8+ features, and how to prevent them from recurring.

Prerequisites and Environment
#

To follow along with the code examples and reproduction scripts, you should have a standard development environment set up. While these errors occur in all versions, our solutions focus on PHP 8.2 and above, as this is the standard for 2025/2026.

Recommended Setup:

  • PHP: Version 8.2 or 8.4.
  • IDE: PhpStorm or VS Code (with Intelephense).
  • Error Reporting: Enabled in your local environment.

Create a simple index.php file to test the examples below. Ensure your php.ini has error reporting turned on for development:

; In your php.ini
display_errors = On
display_startup_errors = On
error_reporting = E_ALL

1. Warning: Cannot Modify Header Information - Headers Already Sent
#

This is arguably the most infamous error in PHP history. It usually looks like this:

Warning: Cannot modify header information - headers already sent by (output started at /path/to/file.php:10)

Why it Happens
#

HTTP protocol rules state that headers (cookies, redirects, content-type) must be sent before any actual content (HTML, text, or whitespace) is sent to the browser. If you echo a string or accidentally leave a blank line before your <?php tag, PHP flushes the headers to the browser. Once flushed, you cannot add new headers.

The Fix
#

Check the file mentioned in the error message (“output started at…”).

The Bad Code:

 <!-- A sneaky space or HTML comment here triggers output -->
<?php
session_start(); // Tries to send a cookie header -> ERROR
header("Location: /dashboard"); // Tries to send Location header -> ERROR
?>

The Solution:

  1. Ensure <?php is the very first distinct character in the file.
  2. Avoid closing ?> tags at the end of pure PHP files to prevent accidental whitespace.
  3. Use Output Buffering if you must mix logic and output (though architectural separation is better).
<?php
// Ideally, turn on output buffering in php.ini: output_buffering = 4096
// Or do it manually in code:
ob_start();

echo "Some content usually breaks headers...";

// Because of buffering, this now works!
header("X-Custom-Header: ItWorks");

ob_end_flush();

2. Warning: Undefined Array Key (Formerly Undefined Index)
#

In older PHP versions, accessing a non-existent array index generated a “Notice.” In modern PHP 8+, this is a “Warning” and should be treated as a bug.

The Scenario
#

You are processing form data or an API response, and a field you expect isn’t there.

The Bad Code:

<?php
$user = [
    'name' => 'John Doe',
    'role' => 'admin'
];

// If 'email' is missing, this throws a Warning
echo "User Email: " . $user['email']; 
?>

The Fix: Null Coalescing Operator (??)
#

Introduced in PHP 7 and perfected in usage by PHP 8, the ?? operator is the cleanest way to handle this. It checks if the key exists and is not null; otherwise, it provides a fallback.

<?php
$user = [
    'name' => 'John Doe',
    'role' => 'admin'
];

// Modern, clean fix
$email = $user['email'] ?? 'Not Provided';

echo "User Email: " . $email;
?>

3. Fatal Error: Maximum Execution Time Exceeded
#

Fatal error: Maximum execution time of 30 seconds exceeded

Why it Happens
#

Your script is taking too long. This usually happens due to:

  1. Infinite Loops: while(true) without a break.
  2. Slow I/O: Waiting for a slow third-party API or a massive database query.
  3. Heavy Processing: Image manipulation or large CSV exports.

The Debugging Workflow
#

Before just increasing the limit, diagnose why it’s slow. Use a logical debugging flow:

flowchart TD A["Bug Reported"] --> B{Is it a Crash/Exception?} B -- "Yes" --> C["Check Error Logs / Sentry"] C --> D["Identify Stack Trace"] B -- "No (Logic Error)" --> E{Is it simple data flow?} E -- "Yes" --> F["Use Ray / Logging"] F --> G["Inspect Variable State"] E -- "No (Complex Logic)" --> H["Enable Xdebug"] H --> I["Set Breakpoints"] I --> J["Step Through Execution"] D --> K["Fix Implemented"] G --> K J --> K K --> L["Run Static Analysis<br/>(PHPStan)"] L --> M["Run Test Suite<br/>(Pest / PHPUnit)"] M --> N["Deploy"] style A fill:#f9f,stroke:#333,stroke-width:2px style N fill:#9f9,stroke:#333,stroke-width:2px style H fill:#ffcccb,stroke:#333

The Fix
#

If the process legitimately takes a long time (e.g., a background job), you can increase the limit temporarily in the script.

<?php
// Allow this script to run for 5 minutes
set_time_limit(300); 

// Better approach for CLI scripts / Background workers:
// ini_set('memory_limit', '512M'); // often needed with time limit increases

$batchSize = 100;
// Simulation of a long process
for ($i = 0; $i < $batchSize; $i++) {
    // Heavy lifting...
    sleep(1); 
}
echo "Batch processing complete.";
?>

Pro Tip: For user-facing web requests, never increase the time limit. Instead, offload the task to a Queue (RabbitMQ, Redis, Amazon SQS).


4. Parse Error: Syntax Error, Unexpected Token
#

This is the most common error for beginners, but even pros miss a semicolon or a brace when refactoring.

Parse error: syntax error, unexpected token "return", expecting ";"

The Fix
#

The error message line number is usually one line after the actual mistake.

The Bad Code:

<?php
function calculateTotal($a, $b) {
    $sum = $a + $b  // Missing semicolon here
    return $sum;    // Error reported on this line
}
?>

Quick Tips:

  1. Look at the line above the reported error.
  2. Check for mismatched brackets {}, (), or []. Modern IDEs highlight these in red/rainbow colors.

5. TypeError: Argument must be of type X, Y given
#

With PHP 8’s strict typing system, this error is becoming more frequent, which is actually a good thing. It prevents data corruption.

The Scenario
#

<?php
declare(strict_types=1);

function addNumbers(int $a, int $b): int {
    return $a + $b;
}

// Fatal Error: Argument #2 ($b) must be of type int, string given
echo addNumbers(10, "20"); 
?>

The Fix
#

You have two options: Cast the data before passing it, or enable weak typing (not recommended). The best approach is to ensure your inputs are sanitized and validated.

<?php
declare(strict_types=1);

function addNumbers(int $a, int $b): int {
    return $a + $b;
}

$input = "20";

// Validate and Cast
if (is_numeric($input)) {
    echo addNumbers(10, (int)$input); // Works: Output 30
} else {
    // Handle error gracefully
    echo "Invalid input provided.";
}
?>

Comparison: The “Emptiness” Checkers
#

Many errors stem from using the wrong function to check if variables exist or have values. Here is a definitive comparison for modern PHP development.

Function Checks if Variable Set? Returns True for null? Returns True for false/0/""? Does it Throw Warning if Undefined? Best Use Case
isset($x) Yes No Yes (it exists) No Checking array keys or optional params.
empty($x) Yes Yes Yes (it’s empty) No Form validation (checking if field is blank).
is_null($x) No (Must exist) Yes No Yes Strict type checking when variable exists.
$x ?? $def Yes No Yes (returns $x) No The Gold Standard for defaults.

6. Parse Error: T_PAAMAYIM_NEKUDOTAYIM
#

This frightening-looking error is Hebrew for “Double Colon” (::).

Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM

Why it Happens
#

You are likely trying to use the Scope Resolution Operator (::) on an object instance incorrectly, or trying to access a static property using arrow syntax (->).

The Bad Code:

<?php
class Database {
    public const DB_NAME = 'prod_db';
}

$db = new Database();

// Incorrect: constants belong to the class, not the instance (in older contexts)
// Or simply syntax confusion inside interpolation
echo $db::DB_NAME; 
?>

The Fix: Use the class name for constants and static methods.

<?php
class Database {
    public const DB_NAME = 'prod_db';
    public static function connect() { return "Connected"; }
}

// Correct usage
echo Database::DB_NAME; 
echo Database::connect();
?>

Conclusion
#

Encountering errors in PHP is not a sign of failure; it is part of the development loop. As we move through 2025, the PHP engine has become stricter, forcing us to write better, more robust code.

Key Takeaways:

  1. Read the error message: It usually tells you the line number and the file.
  2. Use ??: The null coalescing operator is your best friend for arrays.
  3. Strict Types: Embrace declare(strict_types=1) to catch bugs before they hit production.
  4. Logs over Display: In production environments, never display errors to the user (display_errors = Off). Always log them to a file or a monitoring service like Sentry or Datadog.

By understanding these common pitfalls, you can spend less time debugging syntax and more time building value for your users.

Happy coding!