PHPDebugConsole + Error Handler v2.0 No more var_dump()

As told via example:

Built In 0.0144 sec
Peak Memory Usage ?⃝: 4 MB / redacted MB
PHPDebugConsole is great!
No browser plugin necessary
features/options = Array( 0 => PHP port of the javascript web console api outputOpts => Array( 0 => HTML (as seen here) 1 => ChromeLogger 2 => FirePHP 3 => Plain-text / file 4 => <script> 5 => "plugin" (send log realtime via websockets, etc) ) 1 => password protected 2 => errors (even fatal) are captured / logged / displayed 3 => send error notices via email (throttled as to not to send out a flood of emails) 4 => send debug log via email )
New: as of v2.0: now supports styling and substitution
example object = It's Magic Example
properties
private offLimits = I'm a private property
methods
public __toString()
It's Magic
private string foo(string $bar)
types are styled
Array( string => <em>Strings</em><br /> gets visual\u00a0whitespace&trade; and control-char highlighting (hover over the highlights) boolean => true int => 7 float => 123.45 null => null timestamp (string) => 1511429037 numeric string => 42 )
Tables - can sort by column
 citystatepopulation
0AtlantaGA472522
1BuffaloNY256902
2ChicagoIL2704958
3DenverCO693060
4SeattleWA704352
5TulsaOK403090

Quick Start

Installation Option A:

As of v1.2, PHPDebugConsole is installable via Composer as bdk/debug

composer.json
{
	"require": {
		"bdk/debug": "^2.0"
	}
}

Installation Option B:

Download and extract PHPDebugConsole to your webserver

Download PHPDebugConsole

Usage
<?php
require_once 'path/to/Debug.php';   // PHPDebugConsole is PSR-0/4 compliant
									//   require is unnecessary with an autoloader / composer
$debug = new \bdk\Debug(array(
	'collect' => true,
	'output' => true,
));

$debug->log('hello world');

Quality

Build Status
SensioLabsInsight
  • PHPDebugConsole can output the log via the FirePHP and/or ChromeLogger protocols
  • No PHP depenencies required

ChromeLogger

Browser Support:

AJAX Example

Non text/html example


FirePHP

Browser Support:

AJAX Example

Non text/html example

Note: ChromeLogger & FirePHP output is sent via headers…
Debug output must occur before any other output sent to browser.
ob_start() is one way to hold script output until the end of the script.

At a minimum, you must configure either key or both collect and output for the log to be collected & output

Options may be set when instantiating or when getting the instance:
$debug = new \bdk\Debug(array(
	'key' => 'Joshua',
	'emailTo' => 'sfalken@wargames.com',
));
and/or via the setCfg() method:
$debug->setCfg('key', 'Joshua');
$debug->setCfg('emailTo', 'sfalken@wargames.com');
collect
false
Whether the debugger is "on" or not. When false, debug calls are essentially "no-op"

It is not necessary to explicitly set to true if using the key config setting

emailFunc
"email"
A callable that receives 3 parameters: $to, $subject, & $body
emailLog
false
Whether to email a debug log.
values may be:
  • false - log not sent
  • 'onError' (or true) - log sent if there was an error masked by the 'errorHandler/emailMask config value
  • 'always' - log always sent
requires 'collect' to also be true
emailTo
$_SERVER['SERVER_ADMIN']
errorMask
E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR | E_WARNING | E_USER_ERROR | E_RECOVERABLE_ERROR
These errors will appear as "error", remaining errors will appear as "warn"
I am an error
I'm a warning
key

null
Set a "password/key" to enable/view debug info. This key should be passed to the page as a request parameter.

Example:
If we set key to "bosco" and visit our page with the debug param (ie http://mysite.com/path/mypage.php?debug=bosco)
collect will be set to true and
output will be set to true

If we don't pass the debug parameter, or pass the incorrect value, collect and output will both be set to false

key takes precedence over collect and output

file
null
If a valid filepath, log entries to the file. This will supplement the log that is output via output()
logEnvInfo
true
Automatically log essential environment and server vars?

ChangeLog: introduced v2.0

logServerKeys
["REQUEST_URI","REQUEST_TIME","HTTP_HOST","SERVER_NAME","SERVER_ADDR","REMOTE_ADDR"]
If logEnvInfo == true, what $_SERVER vars should be logged?

ChangeLog: introduced v2.0

onBootstrap
null
A callable to be called when debug instance is created
If setting onBootstrap on an existing instance, it will be called immediately

ChangeLog: introduced v2.0

onLog
null
A callable to be called before entry added to log.
Callback will receive a single param: \bdk\PubSub\Event $event.
  • call $event->getSubject() to get the debug object
  • $event['method'] contains debug method
  • $event['args'] contains debug arguments
  • $event['meta'] contains any meta information
  • call $event->stopPropagation() to prevent the entry from being appended to the log.
  • ChangeLog: introduced v2.0

    onOutput
    null
    A callable to be called before log is output.
    Callback will receive a single param: \bdk\PubSub\Event $event.

    ChangeLog: v2.0: passed param changed from $outputAs to \bdk\PubSub\Event

    output
    false
    Should output() actually output the log?

    It is not necessary to explicitly set to true if using the key config setting

    output:
    These options deal with how the log is output:
    addBR
    false
    Convert "\n" to "<br />\n" in strings?
    • unnecessary if styling with white-space: pre (as base css does)
    • applies only to html output
    css
    ''
    Supplemental CSS to output
    • applies only to html output
    filepathCss
    "./css/Debug.css"
    Filepath to base CSS.
    • (need not be publicly accessible)
    • applies only to html output
    filepathScript
    "./js/Debug.jquery.min.js"
    filepath to javascript to include.
    • (need not be publicly accessible)
    • applies only to html output
    outputAs
    null (determine automatically)
    • Seven options out of the box:
      chromeLogger
      Outputs the log via special http headers. Requires browser extension to view.

      Note: Output is sent via headers…
      Debug output must occur before any other output sent to browser.
      ob_start() is one way to hold script output until the end of the script.

      file
      Writes the log to a file specified by the file option
      firephp
      Outputs the log via special http headers. Requires browser extension to view.

      Note: Output is sent via headers…
      Debug output must occur before any other output sent to browser.
      ob_start() is one way to hold script output until the end of the script.

      html
      Outputs the log as HTML, along with accompanying css and javascript
      script
      Outputs the log as <script></script> containing console.xxx calls
      text
      Outputs the log as plain text
      wamp
      • Sends logging in realtime to a WAMP router
      • True console-like logging.
      • Not quite "out-of-the-box" – Requires:
    • If null, will be determined automatically ('html' if non-ajax, content-type: html is being output, 'chromeLogger' otherwise)
    • can also pass an object implementing \bdk\Debug\PluginInterface
    outputCss
    true
    Output default/base CSS?
    • applies only to html output
    outputScript
    true
    Output the filepathScript along with the log?
    • The javascript provides the expand/collapse functionality and adds the Font Awesome icons
    • applies only to html output
    objects
    • These options deal specifically with debugging objects:
    • errorHandler options may be set via the Debug class for convenience
    • These options are new with v1.3
    collectConstants
    true
    Whether to collect object constants
    collectMethods
    true
    Whether to collect object methods, return types, parameter information, etc
    objectsExclude
    ["bdk\\Debug"]
    Array of classes that will not be recursed into if encountered as a property or array value
    Object will be listed as ("(not inspected)")
    objectSort
    "visibility"
    How to sort properties and methods. "visibility", "name", or false|null
    outputConstants
    true
    Whether to output object's constants
    outputMethodDescription
    true
    Whether to output method's long phpdoc description
    outputMethods
    true
    Whether to output object's methods
    useDebugInfo
    true
    Whether to utilize object's __debugInfo magic method when debuging object

    Although __debugInfo is introduced in PHP 5.6, PHPDebugConsole will call the method (if it exists) regardless of PHP version.

    • if __debugInfo value differs from regular value, the property will be listed with indicator icon .
    • If the value came exclusively from __debugInfo, it will be listed with "debug" visibility
    errorEmailer
    • configure how errors notifications are emailed
    • errors are only emailed if not captured by debugger (capture=false at time of error)
    • errorHandler options may be set via the Debug class for convenience
    emailMask
    E_ERROR | E_PARSE | E_COMPILE_ERROR | E_WARNING | E_USER_ERROR | E_USER_NOTICE
    Which types of errors should send an email notice
    emailMin
    15
    Number of minutes that must elapse before resending an email notice for unique errors
    emailThrottleFile
    dirname(__FILE__).'/error_emails.json' A file used to maintain details of recently emailed errors.

    Warning: emailThrottleFile should be set to a path outside the document root or .htaccess should be configured to prevent access / return a 404

    emailTraceMask
    E_ERROR | E_WARNING | E_USER_ERROR | E_USER_NOTICE
    Which types of errors should include a backtrace
    emailThrottledSummary
    true
    Whether to send an email summary of throttled errors on trottle log trash collection
    errorHandler
    • errorHandler options may be set via the Debug class for convenience
    continueToPrevHandler
    true
    PHP only supports one error handler to be defined at a time.
    If this is set true, this handler will pass the error off to the previously set handler (chaining).
    errorReporting
    E_ALL | E_STRICT
    Bitmask for what errors should the errorHandler handle?
    if not handled, and continueToPrevHandler is true, the error will be passed to prev handler
    onError
    null
    Set to something callable. will also get called on fatal errors.
    Callback will receive a single param: \bdk\PubSub\Event $error
    Note: In the examples shown below, instantiation of $debug has been omitted for brevity.
    Note: As of v2.0, all instance methods can now be called statically by prefixing "_" to the method name.
    ie \bdk\Debug::_log('I was logged statically');

    Logging methods

    alert(string $message[, string $class][, boolean $dismissible])

    Display an alert at the top of the log

    This method does not have a web console API equivalent.
    $message
    html to be displayed
    $class
    danger, info, success, or warning
    $dismissible
    (false) Whether to display a close icon/button
    PHP
    $debug->log("pretending to attempt database connection");
    $debug->alert('<i class="fa fa-times-circle fa-lg"></i> Couldn\'t connect the SQL server!');
    $debug->alert('<i class="fa fa-external-link fa-lg"></i> Location: <a class="alert-link" href="#">/some-redirect-url</a>', 'info');
    Output
    Built In 0.0002 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    pretending to attempt database connection
    Ver >= 2.0
    assert(expression, mixed[, mixed...])

    If first argument evaluates false, log the remaining paramaters

    PHP
    $debug->assert(1+1==2, 'basic addition');
    $debug->assert(1*1==2, 'basic multiplication');
    Output
    Built In 0.0001 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    basic multiplication
    count([string $label])

    Log the number of times this has been called with the given label.

    If label is omitted, count() logs the number of times it has been called at this particular line.

    PHP
    $debug->count();
    $debug->count('myCounter');
    for ($i=0; $i<2; $i++) {
    	$debug->count();
    	$debug->count('myCounter');
    }
    $debug->count();
    $debug->count('myCounter');
    Output
    Built In 0.0003 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    count = 1
    myCounter = 1
    count = 1
    myCounter = 2
    count = 2
    myCounter = 3
    count = 1
    myCounter = 4
    error(mixed[, mixed...])

    Log an error message

    PHP
    $debug->log('the four basic methods', 'log', 'info', 'warn', 'error');
    $debug->info('User logged in', false);
    $debug->warn('DROP TABLE', 'Students');
    $debug->error('No Such Table', 'Students');
    Output
    Built In 0.0002 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    the four basic methods, log, info, warn, error
    User logged in = false
    DROP TABLE = Students
    No Such Table = Students
    Supports substitution & formatting, see log() for examples
    Heads Up: htmlspecialchars() is not applied to first argument
    Good
    $debug->error('unsanitized user input', $_GET['whatever']);
    Bad
    $debug->error($_GET['whatever']);
    group([mixed...])

    Creates a new inline group, indenting all following output by another level.

    • To close the group, call groupEnd().
    • If no params are passed, the group's label will default to the current function/method name, or "group" if not inside a function.

    Options

    hideIfEmpty

    Group will be completely hidden (as opposed to collapsed) if it doesn't contain any log entries (or only contains hidden groups)

    Specify by passing a meta argument ie:

    $debug->group('group label', $debug->meta('hideIfEmpty'));

    See exzmple below

    PHP
    $debug->log("This is the outer level");
    $debug->groupCollapsed('Do Stuff');
      $debug->log("Level 2");
      $debug->groupCollapsed('group', 'a', true, null);
        $debug->log("Level 3");
        $debug->warn("Level 3 warning");	// note: error & warn will uncollapse the groups they're in
      $debug->groupEnd();
      $found = isPlaneHere(6.7, 105.62);
      $debug->info('found', $found);
      $debug->log("Back to level 2");
      $debug->group('I\'ll be hidden', $debug->meta('hideIfEmpty'));
      $debug->groupEnd();
    $debug->groupEnd();
    $debug->log("Back to the outer level");
    /**
     * I usually wrap the inner workings of functions in a group
     * note how additional params will appear formatted as if function args
     */
    function isPlaneHere($lat,$lon) {
    	// we'll use the instance methods here in the function
    	//    or we could grab the debug instance with \bdk\Debug::getInstance()
    	\bdk\Debug::_groupCollapsed(__FUNCTION__, $lat, $lon);
    	\bdk\Debug::_log('Analyizing the data...');
    	\bdk\Debug::_groupEnd();
    	return false;
    }
    Output
    Built In 0.0005 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    This is the outer level
    Level 2
    Level 3
    Level 3 warning
    Analyizing the data...
    found = false
    Back to level 2
    Back to the outer level
    groupCollapsed([mixed...])

    Creates a new inline group. Unlike group(), groupCollapse() will initially displayed collapsed*

    • To close the group, call groupEnd().
    • If no params are passed, the group's label will default to the current function/method name, or "group" if not inside a function.

    Options

    groupCollapsed() will start expanded if it contains a nested error or warn, or if groupUncollapse() was used
    hideIfEmpty

    Group will be completely hidden (as opposed to collapsed) if it doesn't contain any log entries (or only contains hidden groups)

    Specify by passing a meta argument ie:

    $debug->group('group label', $debug->meta('hideIfEmpty'));

    See exzmple below

    PHP
    $debug->log("This is the outer level");
    $debug->groupCollapsed('Do Stuff');
      $debug->log("Level 2");
      $debug->groupCollapsed('group', 'a', true, null);
        $debug->log("Level 3");
        $debug->warn("Level 3 warning");	// note: error & warn will uncollapse the groups they're in
      $debug->groupEnd();
      $found = isPlaneHere(6.7, 105.62);
      $debug->info('found', $found);
      $debug->log("Back to level 2");
      $debug->group('I\'ll be hidden', $debug->meta('hideIfEmpty'));
      $debug->groupEnd();
    $debug->groupEnd();
    $debug->log("Back to the outer level");
    /**
     * I usually wrap the inner workings of functions in a group
     * note how additional params will appear formatted as if function args
     */
    function isPlaneHere($lat,$lon) {
    	// we'll use the instance methods here in the function
    	//    or we could grab the debug instance with \bdk\Debug::getInstance()
    	\bdk\Debug::_groupCollapsed(__FUNCTION__, $lat, $lon);
    	\bdk\Debug::_log('Analyizing the data...');
    	\bdk\Debug::_groupEnd();
    	return false;
    }
    Output
    Built In 0.0005 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    This is the outer level
    Level 2
    Level 3
    Level 3 warning
    Analyizing the data...
    found = false
    Back to level 2
    Back to the outer level
    groupEnd();

    Closes the current group

    Every call to group() and groupCollapsed() should be paired with groupEnd()

    PHP
    $debug->log("This is the outer level");
    $debug->groupCollapsed('Do Stuff');
      $debug->log("Level 2");
      $debug->groupCollapsed('group', 'a', true, null);
        $debug->log("Level 3");
        $debug->warn("Level 3 warning");	// note: error & warn will uncollapse the groups they're in
      $debug->groupEnd();
      $found = isPlaneHere(6.7, 105.62);
      $debug->info('found', $found);
      $debug->log("Back to level 2");
      $debug->group('I\'ll be hidden', $debug->meta('hideIfEmpty'));
      $debug->groupEnd();
    $debug->groupEnd();
    $debug->log("Back to the outer level");
    /**
     * I usually wrap the inner workings of functions in a group
     * note how additional params will appear formatted as if function args
     */
    function isPlaneHere($lat,$lon) {
    	// we'll use the instance methods here in the function
    	//    or we could grab the debug instance with \bdk\Debug::getInstance()
    	\bdk\Debug::_groupCollapsed(__FUNCTION__, $lat, $lon);
    	\bdk\Debug::_log('Analyizing the data...');
    	\bdk\Debug::_groupEnd();
    	return false;
    }
    Output
    Built In 0.0005 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    This is the outer level
    Level 2
    Level 3
    Level 3 warning
    Analyizing the data...
    found = false
    Back to level 2
    Back to the outer level
    groupSummary();

    Place log entries at the top of the log

    This method does not have a web console API equivalent.

    A special group used to place log entries at the top of the log

    groupUncollapse()

    changes current and all ancestor groups from groupCollapsed to group

    Have something important to say? Make sure it's initially visible with groupUncollapse

    Note: error(), warn(), and any errors will also uncollapse groups
    PHP
    $debug->groupCollapsed('Turtle 1');
      $debug->groupCollapsed('Turtle 2');
        $debug->groupCollapsed('Turtle 3');
        $debug->log('Working on this bit of code');
        $debug->log('it\'s inside all of these collapsed groups');
        $debug->log('groupUncollapse() opens things up');
        $debug->groupUncollapse();	// jaws of life to the rescue;
    	$debug->info('warn() and error() will also accomplish this');
        $debug->groupEnd();
      $debug->groupEnd();
    $debug->groupEnd();
    Output
    Built In 0.0003 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    Turtle 1
    Turtle 2
    Turtle 3
    Working on this bit of code
    it's inside all of these collapsed groups
    groupUncollapse() opens things up
    warn() and error() will also accomplish this
    info([mixed...])

    Informative logging information

    PHP
    $debug->log('the four basic methods', 'log', 'info', 'warn', 'error');
    $debug->info('User logged in', false);
    $debug->warn('DROP TABLE', 'Students');
    $debug->error('No Such Table', 'Students');
    Output
    Built In 0.0002 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    the four basic methods, log, info, warn, error
    User logged in = false
    DROP TABLE = Students
    No Such Table = Students
    Supports substitution & formatting, see log() for examples
    Heads Up: htmlspecialchars() is not applied to first argument
    Good
    $debug->info('unsanitized user input', $_GET['whatever']);
    Bad
    $debug->info($_GET['whatever']);
    log([mixed...])

    For general logging information

    log(), info(), warn(), & error() methods support formatting
    PHP
    $debug->log('<b>param1</b>');
    $debug->log('<b>param1</b>', '<b>param2</b>');	// two params output as param1 = param2
    $debug->log('<b>param1</b>', 'param2', 'param3'); // more than two params will be separated by ', '
    $debug->log('string', 123, 123.4, '123.4', array('foo'=>'bar'), true, null); // types are styled
    $debug->log('%cNew:%c as of v%.1f: %cnow supports <a target="_blank" href="https://console.spec.whatwg.org/#formatter">styling and substitution</a>',
    	'border:1px outset rgba(0,0,0,.15); border-radius:.33em; background:linear-gradient(to bottom, #fefcea 0%, #f1da36 100%); color:#330; text-shadow: 1px 1px 1px rgba(255,255,255,0.4); font-size:1.3em; font-weight:bold; padding:2px .6em;',
    	'', // empty css... essentially clearing previous styling
    	2.0,
    	'border:#000 solid 1px; box-shadow:2px 1px 0px 0px #000; background-color:rgba(0,0,0,.15); padding:2px .33em; display:inline-block; margin-bottom: .25em;'
    );
    $array = array(
    	'string' => 'foobar',
    	'string_html' => "<span class=\"test\">\r\n\thtmlspecialchar'd &amp; whitespace shown</span>\n",
    	'boolTrue'	=> true,
    	'boolFalse'	=> false,
    	'null'	=> null,
    	'int'	=> 123,
    	'now'	=> time(),	// hover to see formatted (int/float that's +/- 90 days is assumed to be a timestamp)
    	'float'	=> 3.14159265,
    	'numeric' => "123",
    	'string_with_hidden' => "\xef\xbb\xbfPesky <abbr title=\"Byte-Order-Mark\">BOM</abbr>, control char (\x07), and non\xc2\xa0breaking space.",
    );
    $debug->log('array', $array);
    Output
    Built In 0.0003 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    param1
    param1 = <b>param2</b>
    param1, param2, param3
    string, 123, 123.4, 123.4, Array( foo => bar ), true, null
    New: as of v2.0: now supports styling and substitution
    array = Array( string => foobar string_html => <span class="test"> htmlspecialchar'd &amp; whitespace shown</span> boolTrue => true boolFalse => false null => null int => 123 now => 1511429037 float => 3.14159265 numeric => 123 string_with_hidden => \ufeffPesky <abbr title="Byte-Order-Mark">BOM</abbr>, control char (), and non\u00a0breaking space. )
    Heads Up: htmlspecialchars() is not applied to first argument
    Good
    $debug->log('unsanitized user input', $_GET['whatever']);
    Bad
    $debug->log($_GET['whatever']);
    table(array[, string $caption][, array columns])
    table(string $caption, array[, array columns])

    Log an array formatted as a table

    table() takes up to 3 arguments and may be passed in arbitrary order

    • The first encountered array is the table data.
    • The first encountered non-array is treated as a table caption (javascript API does not support caption)
    • If a second array is encountered, it will be used to specify columns to display
    PHP
    $list = array(
    	// note different order of keys / not all rows have all cols
    	array('userId'=>1, 'name'=>'Bob', 'sex'=>'M', 'naughty'=>false),
    	array('userId'=>10, 'naughty'=>true, 'name'=>'Sally', 'extracol' => 'yes', 'sex'=>'F'),
    	array('userId'=>2, 'name'=>'Fred', 'sex'=>'M', 'naughty'=>false),
    );
    $debug->table('people', $list);
    $debug->table('people', $list, array('userId', 'name', 'sex'));
    $debug->log('people', $list);
    Output
    Built In 0.0003 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    people
     userIdnamesexnaughtyextracol
    01BobMfalse
    110SallyFtrueyes
    22FredMfalse
    people
     userIdnamesex
    01BobM
    110SallyF
    22FredM
    people = Array( 0 => Array( userId => 1 name => Bob sex => M naughty => false ) 1 => Array( userId => 10 naughty => true name => Sally extracol => yes sex => F ) 2 => Array( userId => 2 name => Fred sex => M naughty => false ) )

    When output as HTML (as above), the table is sortable by clicking on headers.

    As of v2.0 table() properly handles array of objects
    trace()

    Outputs a stack trace

    essentially debug_backtrace

    PHP
    function func1()
    {
    	call_user_func('func2');
    }
    
    function func2()
    {
        $closure = function () {
    	    \bdk\Debug::_trace();
        };
        $closure();
    }
    
    $debug->alert('This example is pretty weak', 'info');
    func1();
    $debug->info('sorting is disabled for trace tables');
    
    Output
    Built In 0.0006 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    trace
     filelinefunction
    0/path/to/mypage.inc.php11
    1/path/to/mypage.inc.php13{closure}
    2/path/to/mypage.inc.php4func2
    3/path/to/mypage.inc.php17func1
    sorting is disabled for trace tables
    time([string $label])

    Start a timer identified by label

    • This method does not write to the console (use timeEnd() or timeGet() to get elapsed time)
    • If no label specified, a timer is added to a timer stack
    • If timer with passed label already started, this will not reset it
    PHP
    $debug->time('timer a');
    usleep(100);
    $debug->time();		// stack: 0
    usleep(100);
    $debug->time();		// stack: 1
    usleep(100);
    $debug->timeEnd();	// stack: 1
    usleep(100);
    $debug->timeEnd('timer a');	// pauses "timer a" and outputs the running time (does not "end" timer)
    usleep(100);
    $debug->timeEnd();	// stack: 0
    $debug->timeEnd('timer a');
    Output
    Built In 0.0012 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    time: 0.0002 sec
    timer a: 0.0009 sec
    time: 0.0008 sec
    timer a: 0.0009 sec
    timeEnd([string label][, bool|string $returnOrTemplate = "%label: %time sec"])

    Log time elapsed since started with time()

    • If label is passed, the timer is paused. Additional calls to timeEnd('label') will return the same value until unpaused with time('label')
    • If no label is passed, timer is removed from a timer stack and logged
    • $returnOrTemplate: if true, the time will be returned as a float (in seconds) and will not be logged.
      If string, will be used as the template for the output. Default: "%label: %time sec" (as of v1.3.2)
    PHP
    $debug->time('timer a');
    usleep(100);
    $debug->time();		// stack: 0
    usleep(100);
    $debug->time();		// stack: 1
    usleep(100);
    $debug->timeEnd();	// stack: 1
    usleep(100);
    $debug->timeEnd('timer a');	// pauses "timer a" and outputs the running time (does not "end" timer)
    usleep(100);
    $debug->timeEnd();	// stack: 0
    $debug->timeEnd('timer a');
    Output
    Built In 0.0012 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    time: 0.0002 sec
    timer a: 0.0009 sec
    time: 0.0008 sec
    timer a: 0.0009 sec
    timeGet([string $label][, boolean|string $returnOrTemplate = "%label: %time sec"][, integer $precision = 4])

    Get the running time without stopping/pausing the timer

      This method does not have a web console API equivalent.
      PHP: This example shows how to "collect" the time spent inside a function
      queryDb('INSERT INTO student (id, name, age) VALUES ("1", "alan", 28)');
      // other stuff
      queryDb('SELECT * FROM student ORDER BY age');
      // other stuff etc
      $debug->timeEnd('query db');	// total time spent querying
      
      function queryDb($query) {
      	$debug = \bdk\Debug::getInstance();
      	$debug->groupCollapsed(__FUNCTION__, $query);
      	$debug->time('query db');			// start / un-pause
      	// query code omitted
      	$debug->timeEnd('query db', true);	// pause: passing 2nd param so this is "silent"
      	$debug->groupEnd();
      	return $results;
      }
      Output
      Built In 0.0011 sec
      Peak Memory Usage ?⃝: 4 MB / redacted MB
      query db: 0.0005 sec
    warn(mixed[, mixed])

    Log a warning

    PHP
    $debug->log('the four basic methods', 'log', 'info', 'warn', 'error');
    $debug->info('User logged in', false);
    $debug->warn('DROP TABLE', 'Students');
    $debug->error('No Such Table', 'Students');
    Output
    Built In 0.0002 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    the four basic methods, log, info, warn, error
    User logged in = false
    DROP TABLE = Students
    No Such Table = Students
    Supports substitution & formatting, see log() for examples
    Heads Up: htmlspecialchars() is not applied to first argument
    Good
    $debug->warn('unsanitized user input', $_GET['whatever']);
    Bad
    $debug->warn($_GET['whatever']);

    Config & Utility methods

    getCfg(string $what)

    Retrieve a configuration value

    PHP
    /*
    	It would be sacrilege to use print_r or var_dump to view what get() returns
    */
    $debug->log('output', $debug->getCfg('output'));
    $debug->log('outputAs', $debug->getCfg('outputAs'));
    $debug->log('errorEmailer/emailMin', $debug->getCfg('errorEmailer/emailMin'));
    Output
    Built In 0.0002 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    output = true
    outputAs = html
    errorEmailer/emailMin = 15
    meta(string|array $value)

    create meta values

    Currently only used to create a group that will be hidden if empty

    Here a meta argument is passed to a group, specifying that the group should be hidden if it's empty:
    $debug->group('group label', $debug->meta('hideIfEmpty'));

    Meta arguments can be passed to debug methods in any argument position (first/last/somewhere in the middle)

    Meta arguments are used internally to specify information such as what file/line an error occured on

    output()

    "conditionally" output (or return) collected log

    As of v1.2, explicitly calling output() is no longer necessary.. log will be output automatically at end of script

    Log will only be output if either of the following conditions are met

    • output option set to true (default: false)
    • key option set (default: null) and key passed to page as request param (or cookie)
    PHP
    // initialize PHPDebugConsole
    require '/path/to/Debug.php'; // or via autoloader
    $debug = new \bdk\Debug(array(
    	'collect' => true,	// turn logging on
    	'output' => true,	// if left false (default), the output() method will return an empty string
    ));
    $debug->log('hello world');
    echo $debug->output();
    Output
    Built In 0.0001 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    hello world
    setCfg(mixed[, mixed])

    Set one or more configuration options

    Returns previous value

    PHP
    $debug->setCfg('collect', true);
    $debug->setCfg('output', true);
    $debug->setCfg('errorHandler/emailMask', E_ERROR);	// only email error notice for E_ERROR
    // or set multiple values via an array.. values not passed will remain as their current value*
    $debug->setCfg(array(
    	'collect' => 'true',
    	'output' => 'true',
    	'errorHandler' => array(
    		'emailMask' => E_ERROR,
    	),
    ));
    setErrorCaller([array])

    Set the calling/originating source file & line for next error

    Example: you deprecate a function and trigger a E_USER_DEPRECATED error within the function. Rather than reporting that an error occurred on the file/line of trigger_error(), you can use setErrorCaller() to report the error occurring from the file/line that called the function.

    This is is the file/line that will be written to server's error log

    This override will apply until cleared, error occurs, or groupEnd()

    PHP
    trustyOldFunction();
    
    /*
    	PHP's native error_get_last() is only PHP 5 >= 5.2.0
          and error_get_last doesn't play nice with set_error_handler
          https://bugs.php.net/bug.php?id=60575
          use $debug->errorHandler->get('lastError') to get last error
    */
    
    $debug->log('lastError', $debug->errorHandler->get('lastError'));
    function trustyOldFunction() {
    	\bdk\Debug::_setErrorCaller();	// or \bdk\Debug::getInstance()->setErrorCaller()
    	trigger_error('trustyOldFunction\'s days are numbered.  Use superNewFunction instead.', E_USER_DEPRECATED);
    }
    Output
    Built In 0.0007 sec
    Peak Memory Usage ?⃝: 4 MB / redacted MB
    User Deprecated: /path/to/mypage.inc.php (line 1): trustyOldFunction's days are numbered. Use superNewFunction instead.
    lastError = Array( type => 16384 typeStr => User Deprecated category => deprecated message => trustyOldFunction's days are numbered. Use superNewFunction instead. file => /path/to/mypage.inc.php line => 1 vars => Array( 0 => typically this array contains variables defined at scope of error 1 => ommitted from examples ) backtrace => Array() errorLog => false exception => null firstOccur => true hash => 9a3eb856508237011594d8bb7f4cd1e4 suppressed => false email => false stats => Array( tsEmailed => 0 countSince => 0 emailedTo => ) isExampleError => true inConsole => true )

    Version 2.0 introduces events (aka publish/subscribe) that allow allow you to extend PHPDebugConsole and/or create plugins.

    debug.bootstrap

    published when debug is instantiated

    Primarily used internally. This event is published after the debug instance is created. This event can be subscribed to by passing the onBootstrap config option to the debug constructor. If the debug instance has already been instantiated, setting onBootstrap via setCfg will be called immediately.
    debug.config

    published when config is updated

    debug.log

    published after each debug method is called

    • call $event->getSubject() to get the debug object
    • $event['method'] contains the called debug method
    • $event['args'] contains the arguments passed
    • $event['meta'] contains meta information
    • call $event->stopPropagation() to prevent the log-entry from being logged
    debug.objAbstractStart

    published before object is inspected

    This event gives access to the object abstraction before the heavy lifting takes place

    Objects that are excluded from debugging (see objectsExclude config option) or that are recurssion, will not publish this event

    subscribers to this event may:

    set `isExcluded` to true
    set `collectPropertyValues` (boolean)
    set `collectMethods` (boolean)
    set `stringified`
    set this value in lieu of a __toString method..
    example: DateTime objects don't have a __toString() method, so we set stringified to a human readable format
    call $event->getSubject() to get the object being inspected
    debug.objAbstractEnd

    published after object is inspected

    This event gives access to the object abscraction after the heavy lifting took place

    subscribers to this event have complete control to modify the abstraction values:

    call $event->getSubject() to get the object being inspected
    debug.output

    published when it's time to output the log

    subscriber can append $event['output']

    call $event->getSubject() to get the debug instance

    errorHandler.error

    published when a php error occurs

    call $event->getValues() to get all error info

    2.0 – The Refactoring – coming soon

    • fully quallified classname is now \bdk\Debug (was \bdk\Debug\Debug)
    • get() & set() methods renamed to getCfg() & setCfg() respectfully.
    • All instance methods can now be called staticly by prefixing "_" to the method name.
      ie \bdk\Debug::_log('I was logged statically');
    • HUGE HTML rendering performance improvement
      • Pages with lots-o-debug output could take quite some for domReady.
      • Furthermore, it could take a very significant amount of time to enhance the output with collapsibles and icons and whatnot.
      • Could result in unresponsive script / unresponse browser.
    • Object enhancements / fixes:
      • private methods from parent object no longer listed
      • methods used to implement PHP's ArrayAccess, Countable, Iterator, and IteratorAggregate interfaces are now initially hidden. (Visibility toggled via the object's list of implemented interfaces)
      • inherited constants now shown
      • debugging a mysqli instance when not connected would throw "property access is not allowed yet" errors
      • improved docBlock parsing. now handles {@inheritdoc}
      • displayed __toString value is now limited to 100 chars
      • deprecated methods designated as such via muted color and icon
      • ancestor private properties designated as such via muted color and icon
    • String debugging: Unicode "Separator" and other "special" characters are now highlighted
      previously:
      Thanks Obama&copy;
      now:
      Thanks\u00a0Obama&copy;
      That non-break-space character was very easy to miss.
      Htmlentities (ie &nbsp; & &copy;) will still appear as html entities
    • table()
      • now works on arrays of objects (which may implement Traversable)
      • Sortable in HTML output
      • now supports additional argument to specify which columns are displayed
    • log, info, warn, & error methods now support substitution/formatting
    • secondary Debug instances were – in part – still referencing the initial (singleton) instance
    • config() not always setting all values when passing nested arrays
      • Integrated fatal "alert" with error summary.
      • if xdebug installed/enabled:
        • Fatal now displays backtrace
        • Fatal backtrace included in error email
    • New methods
    • New utility method:
      • getIncludedFiles() : get_included_files() plus logical sorting
    • can now pass "hideIfEmpty" "option" to group() and groupCollapsed()
    • group() and groupCollapsed() default label is now calling function's name (or "group" if outside of a function)
    • Arrays matching array(Object, 'string') now recognised as a callable
    • Better handling of single param passed to log, error, info, warn (whether htmlspecialchars & visual whitespace applied)
    • New output options:
      chromeLogger
      ajax and non-html output now defaults to ChromeLogger (was FirePHP)
      Firefox has built in support in, Chrome has an extension
      wamp
      sends log to wamp router in realtime for true console-like logging
    • FirePHP
      • No more dependancy on FirePHP.class.php (aka firephp core library)
        configuration options removed from \bdk\Debug (options were passed to FirePHP.class.php)
      • Check if headers sent before attempting to output
      • File & line information now properly passed with error & warn methods
      • ajax and non-html output now defaults to chromeLogger output rather than FirePHP
    • Internal:
      • error notification email functionality separated from errorHandler.
        errorHandler is now a lean, mean, stand-alone, error-dispatching machine.
      • events/callbacks:
        "callbacks" are now handled via an "event manager" pattern.
        • Multiple "subscribers" can now listen to each event.
        • "Subscriber" can modify event properties, stop propagation, etc.
        • onError and onOutput callbacks now receive \bdk\PubSub\Event object (onError received an array, onOutput received the debug instance)
        • onError: stats array is now populated with current data
        • New event/callback onLog - "published" before data appended to log
          call stopPropagation() on the passed event object to prevent logging
      • microtime stored as float rather than string

    v1.3.2 2015-08-24

    • PHPDoc comment parsing - fixed PREG overflow issue on long comments
    • plain-text output method added
    • CLI debugging defaults to text
    • HTTP_REFERER now included in error email
    • request uri and method now included debug-log email body
    • extends and implements info now output for objects
    • added special case for debugging DOMNodeList objects... now displays the public yet "hidden" length property
    • improved toUtf8 utility method
    • minor css tweaks
    • get() and set() now only have access to configuration
    • added dataGet() and dataSet() methods for directly interacting with the log data
    • timeEnd() and timeGet() accept a template. default: "%label: %time"
    • moved code to "src" folder
    • Utilizing Travis-CI for PHPUnit tests
    • Added and organized unit tests..
    • moved configuration to new Config class
    • removed protected property "collect"... simply use cfg['collect']

    v1.3.1 2015-05-05

    • nested arrays weren't being output via the table() method
    • HTML output now has a checkbox to toggle passing the debug param via cookie
    • setErrorCaller may fail to resolve calling file/line if call_user_func was in the stack trace
    • emailThrottledSummary : new option to disable email summary of throttled errors
      Scenario:
      1. error a occurs… which fires off an error alert email. The error continues to occur but the error is emailed no more than once every emailMin minutes.
      2. error b occurs… which fires off an error alert email. "Trash Collection" is performed on the throttle log. If there is a record of error a (or any other error) having occured more than emailMin minutes ago (and which did not trigger an email notice), a summary of these errors will be emailed

    v1.3 2015-04-01

    • objectExclude option - specify classNames to exclude from inspecting if found nested in array or object properties
    • objectSort option - sort object's properties, methods, & constants by 'name', 'visibility', or unsorted

    v1.3b2 2015-03-17

    • bug #13. Affected debugging objects with properties that weren't declared in the class - PHP bug #69249
    • Object constants are now output
    • Object's __debugInfo method now used if defined
    • Collapsed groups get an indicator if they contain an error or warning
    • New config options useDebugInfo, collectConstants, outputConstants

    v1.3b 2015-02-27

    • Much more detailed output for objects.
      Uses PHP's reflection class - which in turn may read PHPDoc comments - to provide details such as method parameters, return type, visibility, and descriptions.
    • New config settings:
      • emailfunc (default value = "mail")
        Accepts a callable that receivies to, subject, and body. Email's generated by the debugger are passed to this function.
      • collectMethods (default value = true)
      • outputMethods (default value = true)
    • New outputAs option: "script"
      Generates <script> with console calls
    • CSS: Added "m_" prefix to method classnames (.log, .info, .error, .warn, etc)
    • Removed deprecated method setCfg()
    • Removed Utilities::isRecursive()
    • Renamed & shuffled many internal / protected methods

    v1.2 2014-12-03

    • Installable via Composer as bdk/Debug
    • Explicitly calling output() is no longer necessary
    • Param passed to onError function changed from boolean to array
        New Param
        array $error - an array containing all sorts of useful error details.
        If the error is fatal, $error['category'] will be "fatal"
        This is the same array returned by get('lastError')
        Previous
        boolean $isFatal
    • if emailLog is set to "onError", an error matching the ErrorHandler/emailMask mask option must have occured for email to be sent. Previously, any error (incl deprecated) would have qualified.
    • moved errorMask option from ErrorHandler to Debug
    • ErrorHandler class (introduced in v1.1) is now a stand-alone class (no dependencies) and can used completely independently of the debug class.

      Documentation coming soon, but a few core ErrorHandler methods include:

      • getInstance - get the instance of ErrorHandler
      • get and set - get and set config values
      • register & unregister - register/unregister the error handler
      • registerOnErrorFunction($callable) - register an onError "callback"
        • onError function gets passed a single param - array $error
        • Multiple callbacks may be registered
        • Yes, even fatal errors!
      • unregisterOnErrorFunction($callable) - unregister an onError function
      • setErrorCaller - Debug's setErrorCaller() simply calls this
    • Ton of internal reorganization

    v1.1 2014-10-10

    • Dropped PHP4 support
    • Now namespaced namespace bdk\Debug;
    • Internal: now follows PSR-2 coding standard
    • Internal: error-handling methods and functionality now in separate classes
    • Internal: base css moved to Debug.css
    • cfg and data properties are now protected
    • added singleton getInstance method - which is the preferred way to instantiate the class: $debug = \bdk\Debug::getInstance();
    • the javascript is now output with the log (by default) - no need to output/include separately
    • New config options
      • firephpOptions (array)
      • outputScript (boolean) true
      • filepathCss (string) "./Debug.css"
      • filepathScript (string) "./Debug.jquery.min.js"
    • deprecated setCfg(). Use set() (which semantically matches "get()")
    • FirePHP options are now configurable
    • FirePHP's default path changed from ./FirePHP/FirePHP.class.php to ./FirePHP.class.php
    Candy Bars Now
    Geocache

    I Last Twittled:

    • Just released http://t.co/vH5MV7Epzy into the wild. Be free my helpful tool... June 16th, 2014
    • 23 new wrappers added to the collection this weekend - http://t.co/aHED0MgjmA June 2nd, 2013
    • What's the world record for accelerating from 0 to Mach 1? #stratos October 14th, 2012
    • Finally posted 6 new wrappers to the collection http://t.co/OKhoeQOv August 5th, 2012
    • Just added 18 wrappers to the wrapper collection - http://t.co/Fljpm7f6 February 29th, 2012
    Fork me on GitHub