Skip to content

PHP Debugging — Complete Guide to Finding and Fixing Bugs

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about PHP Debugging. We cover key concepts, practical examples, and best practices to help you master this topic.

PHP debugging is the Process of identifying, analyzing, and fixing errors in PHP code using tools like Xdebug, error logs, and stack traces to trace execution flow. This tutorial covers configuring Xdebug with VS Code, interpreting PHP error messages, using var_dump and error_log strategically, handling fatal errors gracefully, and debugging both web and CLI applications.

What You'll Learn

  • Configuring Xdebug for step-through debugging in VS Code and PhpStorm
  • Reading and understanding PHP error messages, stack traces, and log output
  • Using var_dump, print_r, and error_log for quick variable inspection
  • Handling fatal errors and exceptions with custom error handlers
  • Debugging AJAX requests, API responses, and CLI scripts
  • Profiling with Xdebug to find performance bottlenecks

Why It Matters

Every developer writes bugs. The difference between a junior and senior developer is not avoiding bugs but finding them quickly. In production, a single bug can bring down a site, leak data, or corrupt a database. Mastering debugging tools reduces resolution time from hours to minutes, protects your reputation, and keeps your application running smoothly.

Real-World Use

When Doda Browser's sync feature failed silently for users, the engineering team used Xdebug tracing to discover that a Redis connection timeout was caught by a generic try-catch block that logged nothing. Adding proper error logging and debugging instrumentation turned a two-week investigation into a two-hour fix.

Learning Path

flowchart LR
  A[Testing with PHPUnit] --> B[Debugging\nYou are here]
  B --> C[Composer]
  style B fill:#f90,color:#fff

Understanding PHP Error Types

PHP errors fall into several categories, each with a severity level. Familiarize yourself with the most common ones:

  • E_ERROR: Fatal runtime error. Execution stops immediately.
  • E_WARNING: Non-fatal warning. Execution continues.
  • E_PARSE: Compile-time parse error. Code never runs.
  • E_NOTICE: Minor issue like accessing an undefined variable.
  • E_DEPRECATED: Warning about code that will break in a future PHP version.

Configure error reporting in your development environment:

<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('log_errors', '1');
ini_set('error_log', '/var/log/php_errors.log');

Output (no visible output unless an error occurs; error details go to the log file).

Using Xdebug for Step-Through Debugging

Xdebug allows you to set breakpoints, step through code line by line, and inspect variables in real time. Install it:

pecl install xdebug

Configure PHP to load Xdebug. Create /etc/php/8.3/cli/conf.d/99-xdebug.ini:

zend_extension=xdebug
xdebug.mode=debug,develop
xdebug.start_with_request=yes
xdebug.client_port=9003
xdebug.idekey=VSCODE

For VS Code, install the PHP Debug extension and create a .vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Listen for Xdebug",
      "type": "php",
      "request": "launch",
      "port": 9003,
      "pathMappings": {
        "/var/www/html": "${workspaceFolder}"
      }
    }
  ]
}

Set a breakpoint by clicking the gutter in VS Code, start the listener (Run > Start Debugging), and run your script. Execution pauses at the breakpoint, letting you inspect variables and step through code.

Strategic var_dump and error_log

When Xdebug is unavailable, use var_dump with exit to inspect variables:

<?php
function processOrder(array $items, float $discount): float
{
  $total = 0;
  foreach ($items as $item) {
    $total += $item['price'] * $item['quantity'];
  }
  var_dump($total, $discount);
  exit;

  return $total - ($total * $discount);
}

$order = [
  ['price' => 10.00, 'quantity' => 2],
  ['price' => 5.00, 'quantity' => 3],
];
echo processOrder($order, 0.1);

Output:

float(35)
float(0.1)

For production-safe debugging, write to a log file:

<?php
function calculateTotal(array $items): float
{
  $total = array_sum(array_map(fn($item) => $item['price'] * $item['quantity'], $items));
  error_log('calculateTotal: ' . json_encode(['items' => $items, 'total' => $total])); // Logs to /var/log/php_errors.log or stderr
  return $total;
}

$order = [['price' => 25, 'quantity' => 3]];
echo calculateTotal($order);

Output:

75

The log entry appears in your error log:

[28-Jun-2026 12:00:00 UTC] calculateTotal: {"items":[{"price":25,"quantity":3}],"total":75}

Custom Error Handler

Replace PHP's default error handler with one that provides more context:

<?php
set_error_handler(function (int $severity, string $message, string $file, int $line): bool {
  if (!(error_reporting() & $severity)) {
    return false;
  }
  $log = sprintf("[%s] [%d] %s in %s:%d\n", date('Y-m-d H:i:s'), $severity, $message, $file, $line);
  file_put_contents('/var/log/app_errors.log', $log, FILE_APPEND);
  return true;
});

echo $undefinedVariable;

Output (no visible output; error logged to file):

[2026-06-28 12:00:00] [8] Undefined variable: undefinedVariable in /var/www/html/index.php:12

Debugging AJAX and API Requests

When debugging API endpoints, log request details and return structured error responses:

<?php
header('Content-Type: application/json');

try {
  $input = json_decode(file_get_contents('php://input'), true, 512, JSON_THROW_ON_ERROR);
  if (!isset($input['email'])) {
    throw new InvalidArgumentException('Email field is required');
  }
  $result = processRegistration($input['email']);
  echo json_encode(['success' => true, 'data' => $result]);
} catch (\Throwable $e) {
  error_log('API Error: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
  http_response_code(400);
  echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}

Test with curl:

curl -X POST -H "Content-Type: application/json" -d '{"email":"test@example.com"}' http://localhost/api/register

Output:

{"success":true,"data":{"id":42,"email":"test@example.com"}}

Common Mistakes

  1. Relying on var_dump in production: var_dump leaks internal data to users and breaks JSON responses. Use error_log instead and tail the log file.
  2. Ignoring error_reporting settings: If display_errors is off and log_errors is off, you will see a blank white screen with no clue what went wrong.
  3. Not catching exceptions globally: An uncaught exception in PHP 8 produces a 500 error with no helpful output. Wrap your entire application in a try-catch block.
  4. Debugging by adding random echo statements: This clutters output and often misses the root cause. Use a debugger or error log instead.
  5. Not checking log file permissions: If the web server cannot write to the error log, your log entries disappear silently.

Practice Questions

  1. What is the difference between E_WARNING and E_ERROR?

    • E_WARNING is non-fatal — execution continues. E_ERROR stops execution immediately.
  2. How do you enable Xdebug in VS Code?

    • Install the PHP Debug extension, create a launch.json with port 9003, and start debugging with F5.
  3. What is the purpose of error_reporting(E_ALL)?

    • It tells PHP to report all errors, notices, and deprecations. Use it in development to catch every potential issue.
  4. How do you log a variable without stopping execution?

    • Use error_log(json_encode($variable)) to write to the PHP error log without affecting output.
  5. Challenge: Write a custom error handler that sends critical errors (E_ERROR, E_PARSE) to an email address and logs warnings to a file. Test it by triggering both types.

Mini Project

Build a debugging dashboard for a PHP application:

  • Create a Debug utility class with methods for logging, timing execution, and tracking memory usage.
  • Add a global error handler that captures all errors and stores them in an array.
  • Render a debug toolbar at the bottom of HTML pages that shows elapsed time, memory, database queries, and logged errors.
  • Ensure the toolbar only appears in development mode.

FAQ

What is the best PHP debugger?

Xdebug is the most widely used PHP debugger. It integrates with VS Code, PhpStorm, and Sublime Text for step-through debugging and profiling.

How do I debug a PHP CLI script?

Run the script with Xdebug enabled: php -d xdebug.mode=debug script.php. Set breakpoints in your IDE and start the debug listener.

What does a blank white page mean?

A blank white page usually indicates a fatal error with display_errors disabled. Check your error log at /var/log/php_errors.log or add error_reporting(E_ALL) and ini_set('display_errors', '1') at the top of the script.

How do I debug a slow PHP page?

Use Xdebug's profiling mode (xdebug.mode=profile). It generates cachegrind files that you can analyze with tools like KCachegrind or Webgrind to find performance bottlenecks.

Can I debug PHP in Docker?

Yes. Map Xdebug's port (9003) from the container to the host, set the IDE key, and configure path mappings in your IDE. The Docker PHP image includes pecl for Xdebug installation.

What's Next

Master debugging, then learn how to manage dependencies and packages with Composer.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro