Debugging PHP

sa sahaya jerish Updated 20 Oct 2026
6 min read ·Lesson 154 of 155
In this post

What Is Debugging? In simple terms: Debugging is the process of finding out why a program does not do what you expect — and fixing it. A total is wrong, a page is blank, a form saves nothing. Good deb

What Is Debugging?

In simple terms: Debugging is the process of finding out why a program does not do what you expect — and fixing it. A total is wrong, a page is blank, a form saves nothing. Good debugging is not guessing: you observe what the program actually does, narrow down where it differs from what you expected, and confirm the cause before changing code.

Technically: PHP offers several layers of debugging tools: dump functions (var_dump(), print_r(), var_export()), error messages and logs, backtraces (debug_backtrace()), assertions (assert()), step debuggers such as Xdebug (breakpoints, stepping, inspecting variables in an IDE), profilers for performance, and static analysis tools that find bugs without running the code.


A Systematic Approach

1. Reproduce     Find exact steps or input that trigger the bug
2. Observe       Read the error message and logs; inspect values
3. Isolate       Narrow down where actual and expected behavior diverge
4. Hypothesize   Form a specific explanation
5. Verify        Confirm with a dump, breakpoint, or test
6. Fix           Change the code
7. Prevent       Add an automated test that would have caught the bug

 

Most time is lost by skipping steps 2–5 and changing code on a hunch.


Inspecting Values: var_dump(), print_r(), var_export()

<?php
$order = ['id' => 501, 'paid' => true, 'total' => 380.0, 'coupon' => null];

print_r($order);
var_dump($order);
var_export($order);
echo "\n";

 

Output

Array
(
    [id] => 501
    [paid] => 1
    [total] => 380
    [coupon] => 
)
array(4) {
  ["id"]=>
  int(501)
  ["paid"]=>
  bool(true)
  ["total"]=>
  float(380)
  ["coupon"]=>
  NULL
}
array (
  'id' => 501,
  'paid' => true,
  'total' => 380.0,
  'coupon' => NULL,
)

 

FunctionShows Types?Best For
print_r()No (true → 1, null → empty)Quick, readable overview of arrays and objects
var_dump()YesDebugging — types often explain the bug ("5" vs 5, null vs "")
var_export()Yes, as valid PHP codeCopying data into tests or configuration

 

print_r($value, true) and var_export($value, true) return the text instead of printing it, which is useful for logging: error_log(print_r($order, true));.

In a browser, wrap dumps in <pre> tags for readability. The Symfony VarDumper component (composer require --dev symfony/var-dumper) adds dump() and dd() (dump and stop) with colored, collapsible output in browsers and terminals; Laravel includes them by default.

Warning: Remove dumps before committing. A forgotten var_dump() can break JSON responses, prevent redirects ("headers already sent"), or expose data in production.


Where Did This Call Come From? Backtraces

<?php
function callChain(): string
{
    $frames = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
    return implode(' ← ', array_column($frames, 'function'));
}

function applyDiscount(float $amount): float
{
    echo callChain() . "\n";
    return $amount * 0.9;
}

function checkout(): float
{
    return applyDiscount(1000);
}

echo checkout() . "\n";

 

Output

callChain ← applyDiscount ← checkout
900

 

debug_backtrace() returns the current call stack as an array of frames (function, class, file, line, and optionally arguments). DEBUG_BACKTRACE_IGNORE_ARGS omits arguments, which keeps the output small and avoids exposing sensitive values. Exceptions carry the same information: $e->getTraceAsString() shows where an exception was thrown and through which calls (see PHP Exceptions).


Assertions: Catching Impossible States Early

Assertions document assumptions that must always hold. In development, a failed assertion stops execution immediately — close to the real cause:

<?php
function reserveStock(int $quantity): void
{
    assert($quantity > 0);
    // ...
}

try {
    reserveStock(0);
} catch (AssertionError $e) {
    echo "Assertion failed: " . $e->getMessage() . "\n";
}

 

Output (with zend.assertions = 1)

Assertion failed: assert($quantity > 0)

 

zend.assertionsEffect
1 (development)Assertions are evaluated and throw AssertionError on failure
-1 (production default in php.ini-production)Assertions are not even compiled — zero cost

 

Use assertions for programming errors (states that "cannot happen"), never for validating user input — in production they are switched off.


Step Debugging With Xdebug

Dumps show values at one moment. A step debugger pauses the program at a breakpoint, lets you inspect every variable, and execute the code line by line. Xdebug is the standard step debugger for PHP and works with VS Code, PhpStorm, and other IDEs.

Configuration (Development Only)

; conf.d/99-xdebug.ini
zend_extension = xdebug
xdebug.mode = debug,develop
xdebug.start_with_request = trigger
xdebug.client_host = 127.0.0.1        ; in Docker: host.docker.internal
xdebug.client_port = 9003

 

SettingMeaning
xdebug.mode=debugEnables step debugging (develop adds improved error output, profile enables profiling, coverage collects code coverage)
start_with_request=triggerDebug only when a trigger is present, so normal requests stay fast
client_host / client_portWhere the IDE listens for debugging connections (port 9003 by default)

 

VS Code (.vscode/launch.json)

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

 

A Debugging Session

  1. Install the PHP Debug extension in VS Code (or use PhpStorm's built-in support) and start listening.
  2. Set a breakpoint by clicking next to a line number.
  3. Trigger debugging: a browser extension ("Xdebug helper") sets the XDEBUG_TRIGGER cookie; for CLI scripts, run XDEBUG_TRIGGER=1 php script.php.
  4. When execution reaches the breakpoint, inspect variables, the call stack, and evaluate expressions; then step over, step into, or continue.

pathMappings is required when the code runs in Docker or on a VM, where file paths differ from those on your machine.

Warning: Xdebug slows PHP down considerably and allows remote code inspection. Never install it on production servers.


Finding Performance Problems

ToolPurpose
hrtime(true) / microtime(true)Measure the duration of a specific block of code (see PHP Date and Time)
memory_get_usage(), memory_get_peak_usage()Measure memory consumption
Xdebug profiler (xdebug.mode=profile)Records every function call; view the files with KCachegrind, QCachegrind, or PhpStorm
SPX, Blackfire, TidewaysLow-overhead profilers, some usable in production
Database query logs and EXPLAINFind slow or repeated queries (for example, N+1 problems)

 

See OPcache & Performance for configuration-level optimizations.


Preventing Bugs With Static Analysis

Static analysis tools read the code without running it and report type errors, undefined variables, wrong method calls, and impossible conditions:

composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse src --level=6

 

Running PHPStan or Psalm (and php -l for syntax) in continuous integration catches many bugs before anyone needs to debug them. Combined with strict types, typed properties, and automated tests, they make many classic debugging sessions unnecessary.


Common Mistakes

Debugging in Production With display_errors

Effect: Users and attackers see internal details.

Fix: Reproduce locally; use logs and error tracking in production.

Forgotten Dumps

Effect: Broken pages, broken JSON, exposed data.

Fix: Search for var_dump, dd(, and print_r before committing; let static analysis or code review flag them.

Changing Several Things at Once

Effect: You cannot tell which change fixed (or caused) the problem.

Fix: Change one thing, verify, repeat.

Not Writing a Regression Test

Effect: The same bug returns later.

Fix: Capture the failing case in an automated test before or with the fix.


Best Practices

  • Reproduce the bug reliably before changing code.
  • Use var_dump() for precise type information and log structured dumps with print_r(..., true).
  • Use a step debugger (Xdebug) for complex flows instead of scattering dumps.
  • Use assertions for internal assumptions, and static analysis to prevent whole classes of bugs.
  • Keep debugging tools out of production and add a test for every fixed bug.

Official reference: https\://www.php.net/manual/en/debugger.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Home PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else Slicing Strings User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention Garbage Collection Project: Simple Blog PHP What is OOP PHP Classes/Objects The $this Keyword Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where Debugging PHP Project: Image Upload Gallery
Ask about this post
AI Ask about this post

Ask questions about Debugging PHP and get answers drawn from it.

Signed-in readers only.