A Small yet Versatile Debug API for PHP Programs


    "Debugging software is not exactly a fun job for developers. The most widely used debugger for PHP still seems to be a var_dump() statement, possibly in conjunction with die() to halt program execution at a certain point.

    "While there is nothing wrong using var_dump() statements in itself, you still need to change the program code to debug a PHP script. And worse, after you have finished debugging, you must remove all var_dump() statements again (well you should, at least). It may well be that a few days later you'll find yourself adding the very same var_dump() statements to your code again because you need to go hunting another bug.

    "Of course, you could just comment out the var_dump() statements, but that looks really ugly in the code. Another option would be to wrap the var_dump() in conditional clauses, and only execute them when, say, a constant DEBUG is defined. This affects performance, because even if the var_dump() statements are not executed, the conditional clause must be executed. And besides, it looks even uglier in the code."

    - Zend Developer Zone

A Modest Proposal

The archive of this code and text: debug.zip. The code is offered to the public domain, and changing it, adding to it—adapting it— is highly encouraged.

This presents some debug code as a way to have all the benefits of var_dump() statements as Zend Developer Zone says, but without any of the drawbacks they outline. This debug code creates no global data (with one optional exception explained below). It is an API and not a Class.

Instead of var_dump() you use debug() which works similarly, but with a few major exceptions. The displayed data:

In addition, the displayed data includes the file and function name in which the debug() call is used. The result is a list of diagnostic data displayed unobtrusively and under control providing a complete runtime view of the code being debugged.

This release includes a simple version that is one half the original size.

The Setup

The basic operation is to include the file debug.php and strategically place debug() calls throughout your code. If you do just that, nothing will happen and any performance hit will be very small.

Note: I use the term "message" to refer to what debug() logs, but the output depends on it's type (see The Output).

To enable debug output, call the companion function debuglog() with a value to indicate how the debug output will be displayed:

Will cause the messages to be displayed in a list at program termination. These output messages are one per line within a <pre> block with black text and a white background to be independent of the application's HTML (this is configurable).
Will cause the messages to be displayed immediately.
Will cause the messages to be displayed immediately and within HTML comments.
Will cause the messages to be placed in $GLOBALS['debug_messages'], a string, with each message appended with a <br>.

For 1 the output messages are one per line within a <PRE> block with black
text and a white background to be independent of the application's HTML (this
is configurable). (See Terminal Mode.)

For 200 each message is appended with a <BR>. This is so the data can be
incorporated into an application's own HTML output. Such as:

    <div id="debug">
    <?php print $GLOBALS['debug_messages']; ?>

With some appropriate CSS the text can displayed however one sees fit (see the enclosed CSS file for examples).

Note: For an online web application one should only enable debug output if logged in as an Administrator (or via some other mechanism) so that no other visitor sees the output.

The Functions

The function debuglog($log[,$ehand]) turns on debug logging and sets it's value as described above. The optional $ehand is a boolean to install/uninstall the debug error handler, debug_error_handler().

The function debugdump($dump[,$dumps]) turns on debug data dumps and sets it's value. The $dump values are:

Display user added data (explained below).
Display $_GET and $_POST arrays.
Display user defined constants.
Display $GLOBALS.

To add user data to be displayed use a call such as debugdump(1,'data')—the data must be global for only the name of the data is stored; or it could be a function that returns data. The call debugdump(2) is equvalent to debugdump(1,'_GET _POST').

This display is independent from the message log value except that if the log value is 100 this output will be wrapped by HTML comments as well.

The function debug() has two optional arguments. With no arguments the current debug log status is returned; initially 0 or the value set by debuglog().

The first argument is the variable to be displayed. This is usually a string or an array, but booleans, resources and objects are handled in a meaningful way. Arrays are imploded into a string with associative arrays handled correctly. (See The Output.)

The second argument is overloaded. If -1 the message is displayed immediately. If 'type' the first argument is converted by gettype(). If 'dump' the first argument is converted by var_dump().

Additional information is displayed for each message—the file, function and line number of the debug() statement, and optionally, the file and line number of the function that called the function that has the debug() statement.

The function debugfile([$files[,$nofiles]]) is for filtering debug message (see next section) by file name. Both arguments are strings of space delimited file names, the first is for message only from file(s), the second is to ignore messages for files(s).

Example: debugfiles('','formatting.php'). With no arguments the settings are returned as a string like: "files: , nofiles: formatting.php".

The Output

Here is an example of several messages at the end of a program:

    message log:
    (index.php,37)(error.php,51,modules_init) _config_display
    (display.php,742)(data.php,12,load_php_file) 'translate.ini'
    (html.php,47)(data.php,12,load_php_file) 'htm/templates.php'
    (mysql.php,130)(mysql.php,349,_mysql_query) SELECT id FROM root ORDER BY id
    (mysql.php,130)(mysql.php,353,_mysql_query) Object: mysqli_result
    (mysql.php,130)(mysql.php,368,_mysql_query) Array: {1,2,3,4,5,6}

All messages can be converted by htmlentities() so that any HTML in a message will be displayed properly.

The following list is how debug() displays it's first argument:

    Type          Output
    string        "$msg"
    TRUE          "(true)"
    FALSE         "(false)"
    array         "Array {".implode($msg)."}"
    object        "Object ".get_class($msg)
    resource      "Resource ".get_resource_type($msg)
    empty string  "(empty)" (dependent on DEBUG_EMPTY_STR define)

A $msg of NULL will produce no output (it would cause debug() to return it's value). Often one can mitigate that by: debug("'$msg'"), with NULL showing as ''. Or one can do: debug($msg,'dump').

The Options

Other than the options set by the three control functions, other output controls are set be defines. The defines can be set by editing the source file directly or by defining the before including it. The major defines are:

    DEBUG_OPEN          "\n<div style='background:#fff;color:#000;'><pre>"
    DEBUG_CLOSE         '</pre></div>';
    DEBUG_MSG           "\n<b>message log:</b>\n"
    DEBUG_EMPTY         1
    DEBUG_CALLER        1
    DEBUG_TRUNC         200
    DEBUG_CONVERTNL     '\n'

The OPEN and CLOSE strings get displayed before and after the debug output, MSG precedes the debug message list. If the EMPTY option is true MSG will be displayed even if there are no messages.

The CALLER option adds two levels of function call data. The TRUNC option will cause all messages to be truncated to it's value if greater than zero. The EMPTY_STR option will cause empty string to be displayed as (empty). The CONVERTNL option converts newlines in the data to it's value (define DEBUG_NOCONVERTNL to not convert newlines).

In addition, DEBUG_LOG and DEBUG_ERR are used to set the log level or install the debug error handler (and the same as calling debuglog(DEBUG_LOG) and debugdump(-1,DEBUG_DUMP) respectively).

Other Functions

The code includes a few non-documented functions: debug_dump() is a variation of var_dump(); debug_caller() is used to get the caller of a function with levels, such as the caller of the caller (and it can also return two versions of a backtrace).


If your code has redirects by header("Location: $URL"), or has direct downloads by header("Content-Type: text/plain"), any debug output will interfere. That can be mitigated by preceding such statements with debuglog(0) to turn the output off.

Terminal Mode

For using this code for a command line program, you can define DEBUG_TERM to true and all output will be adjusted—no HTML—and all output goes to STDERR. If $argv is set the code defaults to terminal mode.

Debugging Wordpress

The code can be used with WordPress but there are two caveats. First, including the API and enabling debugging in wp-config.php (the recommended file for making customizations) means that many of WordPress' files cannot be debugged as they are loaded before wp-config.php. For temporary debugging placing code like:

    include 'debug.php';
    debugdump(1,'wp_smiliessearch wpsmiliestrans');

at the top of the file containing the code to debug works fine. (I have not fully investigated the WordPress file load process, but it looks like wp-load.php might be a good place to temporarily put the debug start code.)

The other caveat is that I do not know how to test for being logged in as an administrator. WordPress says in function is_admin(): "Does not inform on whether the user is an admin! Use capability checks to tell if the user should be accessing a section or not." I do not know what that means.

When debugging a function that is called many times, like wptexturize(), place the debug start code at the top of the file (formatting.php) and use something like this:

    static $debug = 0;
    if ($debug == 0) {
    	$debug = 1;

(If you do that you may see a flaw in the data.)

You can also add an option, say debug, and use this:


But WordPress is so complicated that I cannot find where in the load process that get_option() becomes available for use; i.e. many functions you may want to debug are called before get_option() is available.

So I give up there.

Change Log

Version 2.1.0

Written by Greg Jennings; last update Augut 2015.

Comment on this code at SourceForge

Visit Debug on GitHub.

See also: GMLPRulesWordBash