Loading…

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

Overview & Usage

    • 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
      )
    • Styling: as of v2.0: 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 /> get visual\u00a0whitespace&trade; and control-char highlighting (hover over the highlights)
        • boolean yea=>true
        • boolean nay=>false
        • int=>7
        • float=>123.45
        • null=>null
        • timestamp (string)=>1614976294
        • numeric string=>42
        )
    • Table - Click headings to sort
       citystatepopulation
      0AtlantaGA472522
      1BuffaloNY256902
      2ChicagoIL2704958
      3DenverCO693060
      4SeattleWA704352
      5TulsaOK403090

    Quick Start

    Installation Option A:

    Install via Composer as bdk/debug (as of v1.2)

    Add to composer.json

    {
        "require": {
            "bdk/debug": "dev-master"
        }
    }

    or

    composer require bdk/debug:dev-master --update-no-dev

    Note that v3.0 has not yet been released, so we're specifying "dev-master" above

    Installation Option B:

    Download and extract PHPDebugConsole to your webserver

    Download PHPDebugConsole

    Usage
    <?php
    require __DIR__.'/vendor/autoload.php';		// if installed via composer
    // require 'path/to/Debug.php';   			// if not using composer
    
    $debug = new \bdk\Debug(array(
    	'collect' => true,
    	'output' => true,
    ));
    
    $debug->log('hello world');

    Quality / Badges

    • No Dependencies
    • Build Status
    • SensioLabsInsight

    Features

    • Automatically outputs to HTML, ChromeLogger, or stream according to environment / request
    • Channels:
      • Log PDO/SQL related entries in a "PDO" channel. Log guzzle, it a "guzzle" channel. Log routing info in a "route" channel. etc
      • Html output can be filtered by channels. Other routes can filter what they handle / output by channel name.
    • HTML output features
      • Collapsable drawer docked to bottom of viewport.. (look at bottom of window for example)
      • filter sidebar - filter by channel, or log-level (alert, error, warning, info, other)
      • syntax highlighted json, xml, sql, php
      • editor links (click on error or file to open relevant file/line in your editor/IDE)
      • fatal error backtraces get context (file-snippets)
    • Automatically email fatal error details to SERVER_ADMIN (configurable)
    • Methods may be called statically or as an instance method
      To call statically, prefix the method name with an underscore
      example: \bdk\Debug::_log('I was logged statically');
    • Logs environment, request/response, $_SESSION, & files included during request. If using a framework extension/bundle, more information may be logged
      • Php Version, ini file(s) location, configured timezone, memory limit
      • If error reporting is less than E_ALL | E_STRICT
      • Checks if expose_php is disabled, whether common extensions, curl & mbstring enabled, whether xdebug is enabled
    • Plugins/collectors for Guzzle, Monolog, Mysqli, PDO, PhpCurlClass, PSR-3 (logger), PSR-16 (SimpleCache), SoapClient, SwiftMailer, & Twig. See documentation.

    Strings

    • Control chars & non-visual chars shown
    • Base64, json, & serialized detected & inspected. (serialized only unserialized if safe to do so)
    • HTML, json, SQL, & XML prettified. (Other formats may be prettified via plugin)
    • Binary strings inspected and mime/content-type shown
    • Numeric strings tested if timestamp and (readable date time shown)
    String Examples
      • value a = 1614976294
      • value b = \ufeffThis string has it all: <ul> <li>Pesky <abbr title="Byte-Order-Mark">BOM</abbr></li> <li>HTML</li> <li>control chars: </li> <li>easy-to-miss characters such as \u00a0(nbsp), \u2009(thsp), &amp; \u200b(zwsp).</li> </ul>
      • value c =
        iVBORw0KGgoAAAANSUhEUgAAAcIAAAA/CAMAAAEzugiSAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAAAMBQTFRF+pMFrgIC9PHp0mNlcF1gXlSo2s/JjWZiDgWTklUTTiMf69sI … 13100 more bytes (not logged)
        binary string
        • mime type = image/png
        • size = 9687
        • Binary data not collected
      • value d =
        (prettified) { "poop": "\ud83d\udca9", "int": 42, "password": "█████████" }
        array(
        • poop=>💩
        • int=>42
        • password=>█████████
        )
      • value e =
        a:3:{i:0;s:5:"phone";i:1;s:6:"laptop";i:2;s:7:"desktop";}
        array(
        • 0=>phone
        • 1=>laptop
        • 2=>desktop
        )

      Objects

      PHPDebugConsole dumps just about every piece of info you would need to know about an object

      • Classname
      • Interfaces
      • Inheritance
      • Final?
      • Constants
        • Name
        • Value
        • Attributes (PHP 8)
        • PhpDoc description (PHP 7.1)
        • Visibility (PHP 7.1)
      • Properties
        • Name
        • Type
        • Value

          Did value come from object's debugInfo() method?

        • Visibility - public | protected | private | magic | magic-read | magic-write | debug
          Can can be combination of the above (example private magic-read)
        • Attributes (PHP 8)
        • Inheritance
          (Where was it last declared?)
        • PhpDoc description
        • Promoted (PHP 8)
        • Static?
      • Methods
        • Name
        • Visibility - public | protected | private | magic
        • If implements interface / can show/hide interface methods for ArrayAccess, Countable, Iterator, IteratorAggregate
        • Attributes (PHP 8)
        • Inheritance
          (Where was it last declared?)
        • Deprecated?
        • Final?
        • Static?
        • PhpDoc description
        • Return type & PhpDoc description
        • Parameters
          • name
          • type
          • optional?
          • default value
          • Attributes (PHP 8)
          • Promoted? (PHP 8)
          • PhpDoc description
      • PhpDoc tags
      • Attributes (PHP 8)

        PHP Attributes are inspected for Class, Constants, Properties, Methods, Method Params

      • Anonymous?
      Example Object
        • Click on the classname or [+] expandy below to inspect the object
        • array(
          • Once expanded, hover over various things for tooltips
          • Click on the toggle button at the top to show/hide protected, private, etc
          • Click on "ArrayAccess" to toggle showing ArrayAccess methods
          )
        • this is the __toString return value Acme\Widget
          final
          extends
          Acme\Component
          implements
          ArrayAccess
          attributes
          Acme\Attributes\ExampleClassAttribute(foo, bar:baz)
          constants
          public EVENT_RENDER = widget.render
          properties (via __debugInfo)
          This object has a __get method
          public baz = the 'ol __debugInfo a'roo
          public static string encoding = UTF-8
          protected int count = 10
          private Acme\GiantObj bar = NOT INSPECTED
          private (Acme\Component) array foo = array()
          magic thing = I'm not included in debugInfo #reasons
          debug blah = I'm returned in __debugInfo, but not otherwise a property
          methods
          This object has a __call method
          public __construct(int $count)
          public mixed __call(string $name, array $arguments)
          public array __debugInfo()
          public mixed __get(string $name)
          public string __toString()
          this is the __toString return value
          public static array getFlags()
          public illConceived(string $version = PHP_VERSION, string &...$key)
          public bool offsetExists(string $key)
          public mixed offsetGet(string $key)
          public void offsetSet(string $key, mixed $key)
          public void offsetUnset(string $key)
          final public string run()
          protected someInternalThing()
          private somePrivateThing()
          magic Acme\Response shazam()
          phpDoc
          author: James Acme <james@example.com>

        Methods

        Note: In the examples below, instantiation of $debug has been omitted for brevity.

        Note: As of v2.0, all instance methods can be called statically by prefixing "_" (underescore) to the method name.
        example: \bdk\Debug::_log('I was logged statically');

        Logging methods

        alert(string $message[, string $level = error[, bool $dismissible = false]])

        Display an alert at the top of the log

        Parameters

        $message
        html to be displayed
        $level
        error, info, success, or warn
        "danger" & "warning" are still accepted, however deprecated
        $dismissible
        (false) Whether to display a close icon/button

        Can use styling & substitutions.
        If using substitutijons, will need to pass $level & $dismissible as meta values

        This method does not have a web console API equivalent.
        Example Source
        $debug->log("pretending to attempt database connection");
        $debug->alert('Couldn\'t connect to the SQL server!', $debug->meta('icon', 'fa fa-times-circle fa-lg'));
        $debug->alert('Location: <a class="alert-link" href="#">/some-redirect-url</a>', 'info', $debug->meta(array(
            'icon' => 'fa fa-external-link fa-lg',
            'sanitize' => false,
        )));
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • pretending to attempt database connection
        Changelog:
        • v3.0 - danger & warning levels replaced with error & warn
        • v2.0
        assert(bool $assertion[, mixed ...$msg = null])

        If first argument evaluates false, log the remaining paramaters

        Parameters

        $assertion
        Any boolean expression. If the assertion is false, the message is logged
        ...$msg
        (optional) variable num of values to output if assertion fails
        if none provided, will use calling file & line num
        Example Source
        $debug->assert(1+1==2, 'basic addition');
        $debug->assert(1*1==2, 'basic multiplication');
        $debug->assert(false);  // no message parameter
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • basic multiplication
        • Assertion failed: /path/to/mypage.inc.php (line 3)
        Supports substitution & formatting, see log() for examples
        Changelog:
        • v2.3: Support for substitution & formatting
        • v2.0: Default message used if none passed
        clear([int $flags = self::CLEAR_LOG])

        Clear the log

        This method executes even if collect is false

        Parameters

        $flags
        A bitmask of options
        self::CLEAR_ALERTS : Clear alerts generated with alert()
        self::CLEAR_LOG : default Clear log entries (excluding warn & error)
        self::CLEAR_LOG_ERRORS : Clear log, warn, & error
        self::CLEAR_SUMMARY : Clear summary entries (excluding warn & error)
        self::CLEAR_SUMMARY_ERRORS : Clear summary warn & error
        self::CLEAR_ALL : clear all everything
        self::CLEAR_SILENT : Don't add log entry
        Example Source
        $debug->log('now you see me');
        $debug->error('yikes, I\'m an error');
        $debug->clear();
        $debug->info('hover over "cleared" entry for file & line');
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • yikes, I'm an error
        • Cleared log (sans errors)
        • hover over "cleared" entry for file & line
        Changelog:
        • v2.2
        count([mixed $label = null[, int $flags = null]])
        count(int $flags)

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

        Count is maintained even when collect is false
        If collect = false, count() will be performed "silently"

        Parameters

        $label
        Label. If omitted, logs the number of times count() has been called at this particular line.
        $flags
        (optional) A bitmask of
        \bdk\Debug::COUNT_NO_INC: don't increment the counter<br /> (ie, just get the current count)<br /> \bdk\Debug::COUNT_NO_OUT : don't output/log

        Return Value

        int
        The new count (or current count when using COUNT_NO_INC)
        Example Source
        $debug->count();
        $debug->count('myCounter');
        for ($i=0; $i<2; $i++) {
            $debug->count();
            $debug->count('myCounter', \bdk\Debug::COUNT_NO_OUT); // don't output now
        }
        $debug->log('after loop');
        $debug->count();
        $debug->count('myCounter');
        echo 'myCounter value = '.$debug->count('myCounter', \bdk\Debug::COUNT_NO_INC | \bdk\Debug::COUNT_NO_OUT); // don't increment or output, just return
        Example Output
        myCounter value = 4
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • count = 1
        • myCounter = 1
        • count = 1
        • count = 2
        • after loop
        • count = 1
        • myCounter = 4
        Changelog:
        • v2.1: $flags argument added
        countReset([mixed $label = null[, int $flags = null]])
        countReset(int $flags)

        Resets the counter

        Counter is reset even when debugging is disabled (ie collect = false).

        Parameters

        $label
        (optional) specify the counter to reset
        $flags
        (optional) currently only one option :
        \bdk\Debug::COUNT_NO_OUT` : don't output/log
        Example Source
        $debug->count('myCounter');
        for ($i=0; $i<2; $i++) {
            $debug->count('myCounter', \bdk\Debug::COUNT_NO_OUT); // don't output now
        }
        $debug->log('after loop');
        $debug->count('myCounter');
        $debug->log('do the reset');
        $debug->countReset('myCounter');
        $debug->log('get count without incrementing...');
        $debug->count('myCounter', \bdk\Debug::COUNT_NO_INC);
        $debug->log('calling count after reset');
        $debug->count('myCounter');
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • myCounter = 1
        • after loop
        • myCounter = 4
        • do the reset
        • myCounter = 0
        • get count without incrementing...
        • myCounter = 0
        • calling count after reset
        • myCounter = 1
        Changelog:
        • v2.3
        error([mixed ...$arg = ])

        Log an error message.

        Parameters

        ...$arg
        message / values
        Example Source
        $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');
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 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
        Changelog:
        • v3.0: first param now gets htmlspecialchar()'d by default
          use meta('sanitizeFirst', false) to allow html
        group([mixed ...$arg = ])

        Create a new inline group

        Parameters

        ...$arg
        label / values
        Meta options (see meta)
        option description since
        argsAsParams (true) 3.0
        boldLabel (true) 3.0
        hideIfEmpty (false) Group will be completely hidden (as opposed to collapsed) if it doesn't contain any log entries (or only contains hidden groups) 2.0
        isFuncName (false) 3.0
        level (null) "error", "info" or "warn" 2.0
        ungroup (false) Group will be converted to log entry if 1 or fewer log entries 3.0
        • 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.
        Example Source
        $debug->log("This is the outer level");
        doStuff();
        $debug->log("Back to the outer level");
        function doStuff() {
            // we'll grab the debug instance with \bdk\Debug::getInstance()
            $debug = \bdk\Debug::getInstance();
            $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();
        }
        function isPlaneHere($lat,$lon) {
            // we'll use the static methods here
            // note how additional params will appear formatted as if function args
            \bdk\Debug::_groupCollapsed(__FUNCTION__, $lat, $lon);
            \bdk\Debug::_log('Analyizing the data...');
            $return = false;
            \bdk\Debug::_groupEnd($return);
            return $return;
        }
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • This is the outer level
        • doStuff
          • Level 2
          • group(a, true, null)
            • Level 3
            • Level 3 warning
          • found = false
          • Back to level 2
        • Back to the outer level
        groupCollapsed([mixed ...$arg = ])

        Create a new inline group

        Parameters

        ...$arg
        label / values
        Meta options (see meta)
        option description since
        argsAsParams (true) 3.0
        boldLabel (true) 3.0
        hideIfEmpty (false) Group will be completely hidden (as opposed to collapsed) if it doesn't contain any log entries (or only contains hidden groups) 2.0
        isFuncName (false) 3.0
        level (null) "error", "info" or "warn" 2.0
        ungroup (false) Group will be converted to log entry if 1 or fewer log entries 3.0
        • 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.
        groupCollapsed() will be expanded if it contains a nested error or warn, or if groupUncollapse() was used
        Example Source
        $debug->log("This is the outer level");
        doStuff();
        $debug->log("Back to the outer level");
        function doStuff() {
            // we'll grab the debug instance with \bdk\Debug::getInstance()
            $debug = \bdk\Debug::getInstance();
            $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();
        }
        function isPlaneHere($lat,$lon) {
            // we'll use the static methods here
            // note how additional params will appear formatted as if function args
            \bdk\Debug::_groupCollapsed(__FUNCTION__, $lat, $lon);
            \bdk\Debug::_log('Analyizing the data...');
            $return = false;
            \bdk\Debug::_groupEnd($return);
            return $return;
        }
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • This is the outer level
        • doStuff
          • Level 2
          • group(a, true, null)
            • Level 3
            • Level 3 warning
          • found = false
          • Back to level 2
        • Back to the outer level
        groupEnd([mixed $value = bdk\Debug\Abstraction\Abstracter::UNDEFINED])

        Close current group

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

        The optional return value will be visible when the group is both expanded and collapsed.

        Parameters

        $value
        (optional) "return" value
        Example Source
        $debug->log("This is the outer level");
        doStuff();
        $debug->log("Back to the outer level");
        function doStuff() {
            // we'll grab the debug instance with \bdk\Debug::getInstance()
            $debug = \bdk\Debug::getInstance();
            $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();
        }
        function isPlaneHere($lat,$lon) {
            // we'll use the static methods here
            // note how additional params will appear formatted as if function args
            \bdk\Debug::_groupCollapsed(__FUNCTION__, $lat, $lon);
            \bdk\Debug::_log('Analyizing the data...');
            $return = false;
            \bdk\Debug::_groupEnd($return);
            return $return;
        }
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • This is the outer level
        • doStuff
          • Level 2
          • group(a, true, null)
            • Level 3
            • Level 3 warning
          • found = false
          • Back to level 2
        • Back to the outer level
        Changelog:
        • v2.3: accepts $value parameter
        groupSummary([int $priority = 0])

        Open a "summary" group

        Debug methods called from within a groupSummary will appear at the top of the log.
        Call groupEnd() to close the summary group

        All groupSummary groups will appear together in a single group

        This method does not have a web console API equivalent.

        Parameters

        $priority
        (0) The higher the priority, the earlier it will appear.
        Example Source
        $debug->log('foo');
        
        $debug->groupSummary();
        $debug->log('I\'m at the top of the log');
        $debug->groupEnd();
        
        $debug->groupSummary(1);
        // get the current git branch we're working on and display it
        exec('git branch | grep \* | cut -d " " -f2', $gitCmdOutput);
        $debug->log(
            '%c<i class="fa fa-github" aria-hidden="true"></i>%s',
            'font-size:1.5em; background-color:#ddd; padding:1px 3px;',
            $gitCmdOutput[0],
            $debug->meta('sanitizeFirst', false)
        );
        $debug->groupEnd();
        
        $debug->info('as of v3.0, the git branch is logged by default');
        Example Output
        • feature/groupSummary
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • I'm at the top of the log
        • foo
        • as of v3.0, the git branch is logged by default
        "Built in" & "Peak Memory Usage" are appended to the priority-1 group just before the log is output.
        groupUncollapse()

        Uncollapse ancestor groups

        This will only occur if cfg['collect'] is currently true

        This method does not have a web console API equivalent.
        Note: error(), warn(), and any errors will also uncollapse groups
        Example Source
        $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();
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 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 ...$arg = ])

        Log some informative information

        Parameters

        ...$arg
        message / values
        Example Source
        $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');
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 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
        Changelog:
        • v3.0: first param now gets htmlspecialchar()'d by default
          use meta('sanitizeFirst', false) to allow html
        log([mixed ...$arg = ])

        Log general information

        Parameters

        ...$arg
        message / values
        Example Source
        $debug->log('param1');
        $debug->log('param1', 'param2');    // two params output as param1 = param2
        $debug->log('param1', '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('%Styling:%c as of v%.1f: %csupports <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;',
            $debug->meta('sanitizeFirst', false)
        );
        $array = array(
            'string' => 'foobar',
            'string_html' => '<span class="test">'."\r\n\t".'htmlspecialchar\'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);
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • param1
        • param1 = param2
        • param1, param2, param3
        • string, 123, 123.4, 123.4, array(
          • foo=>bar
          )
          , true, null
        • %Styling: as of v0.0: supports styling and substitution = 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"> htmlspecialchar'd &amp; whitespace shown</span>
          • boolTrue=>true
          • boolFalse=>false
          • null=>null
          • int=>123
          • now=>1614976294
          • float=>3.14159265
          • numeric=>123
          • string_with_hidden=>\ufeffPesky <abbr title="Byte-Order-Mark">BOM</abbr>, control char (), and non\u00a0breaking space.
          )
        assert(), log(), info(), warn(), & error() methods support formatting (aka substitution)
        Changelog:
        • v3.0: first param now gets htmlspecialchar()'d by default
          use meta('sanitizeFirst', false) to allow html
        profile([string $name = null])

        Starts recording a performance profile

        Parameters

        $name
        Optional Profile name
        How it works:
        • Uses PHP's register_tick_function() under the hood… which requires declare(ticks=1); be declared in any code-block/file that contains funcitons/methods/code to be profiled. (yuck)
        • enableProfiling to the rescude
        Example Source
        /*
            enablePofiling must be set before files containing code to be profiled are included
            (should be set when instantiating PHPDebugConsole)
        */
        $debug->setCfg('enableProfiling', true);
        $debug->profile();
        // build a html form
        //    this is real-world.  guess the framework
        //    how many classes and calls does it take to build a form?!
        // ...
        $debug->profileEnd();
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • Profile 'Profile 1' started
        • Profile 'Profile 1' Results
           callstotalTimeownTime
          CBaseController::beginWidget10.6497570.016487
          CModule::__get350.3743570.001115
          BootActiveForm::inputRow340.3723180.002285
          BootInput::run340.3495550.005287
          CModel::getValidators1310.3051930.087937
          CHtml::openTag340.2728060.001669
          BootInput::getLabel270.243550.001747
          BootActiveForm::dropDownListRow80.1663880.000251
          CListIterator::next28510.1620770.162077
          CModel::isAttributeRequired730.1589480.005975
          BootActiveForm::textFieldRow180.1587010.000439
          CActiveForm::dropDownList90.1197840.000368
          CHtml::activeDropDownList90.1168680.00125
          CHtml::tag3720.1145030.012069
          CHtml::resolveValue400.1118830.026433
          CHtml::renderAttributes4090.1112580.111258
          CActiveForm::textField190.0733670.000563
          CHtml::activeTextField190.0671020.00162
          CHtml::activeInputField230.0613790.004848
          WForm::label270.0490110.002613
          CModel::createValidators10.0414180.000133
          BootActiveForm::checkBoxRow70.0406090.000235
          buildCustField30.0374630.001219
          AppSettingManager::get40.0313540.000555
          MyModel::rules10.0310990.000325
          WForm::resolveArgs480.027970.010955
          ValidationRule::model10.0256956.5E-5
          YiiBase::log160.0250590.004995
          CList::getIterator1510.0221660.005364
          CLogger::log160.0200650.002577
          CComponent::__get350.0194560.002591
          CDbCommand::getText160.0191840.00109
          WForm::checkBox70.0189220.000215
          CActiveForm::label270.0181920.001984
          CActiveRecord::model10.0178529.1E-5
          CLogger::flush160.0174880.001229
          CListIterator::__construct1510.0168020.016802
          AccessManager::isAllowed20.0167740.000702
          include180.0164720.010252
          CEvent::__construct160.0162590.001548
          CHtml::activeLabel270.0162080.004621
          CActiveRecordMetaData::__construct10.0161780.000325
          CActiveForm::checkBox70.0158750.000245
          CDbSchema::getTable10.0158530.000114
          CMysqlSchema::loadTable10.0157396.8E-5
          CMysqlSchema::findColumns10.0155620.000515
          CActiveRecord::query20.0151920.000198
          WForm::resolveName990.0147460.014746
          CComponent::raiseEvent160.0147110.00158
          CDbConnection::createCommand40.0138270.000416
          CWidgetFactory::createWidget340.0136040.009948
          CDbCommand::queryRow20.0123910.000661
          CDbCommand::__construct40.0122410.001517
          CModule::getComponent20.0117870.000314
          AccessRole::isAllowed100.011730.000417
          CHtml::label270.0115870.003098
          SAML2_autoload80.0114580.00304
          BootActiveForm::error340.0108590.006517
          CHtml::activeCheckBox70.010530.000966
          CDbCommand::queryInternal20.0104790.001404
          ValidationRuleManager::findOptionsByModel10.0102833.9E-5
          CValidator::createValidator200.0100670.004505
          WForm::hiddenField40.0095780.000119
          CLogRouter::collectLogs160.0095280.003129
          CActiveRecord::find10.009266.0E-5
          spl_autoload_call60.0090630.000206
          YiiBase::import100.0088990.001484
          CBaseController::createWidget10.0088952.8E-5
          CHtml::hiddenField80.0084330.000782
          WForm::resolveModel560.0078340.007834
          CWebApplication::getWidgetFactory10.007699.8E-5
          BootActiveForm::checkBoxListRow10.0075692.4E-5
          YiiBase::autoload80.007520.000231
          WebUser::__get120.0073430.000347
          CLogRoute::collectLogs320.0063990.00285
          AccessRule::match100.0063490.002645
          WForm::resolveAttribute1010.0059550.005955
          CHtml::inputField110.0058290.001498
          CHtml::resolveNameID400.0056240.005476
          YiiBase::trace30.0055790.000144
          WebUser::_getModel200.005440.00057
          CWebUser::__get200.005260.000473
          ActiveRecord::__get650.0052290.004732
          BootActiveForm::checkBoxList10.0051453.3E-5
          WebUser::getState390.0050630.001931
          CWebUser::hasState200.0047870.001617
          BootActiveForm::inputsList10.0044150.000679
          BootActiveForm::getErrorHtml340.0043420.002017
          AppSettingManager::arrayPath180.0043080.004308
          YiiBase::getPathOfAlias30.003930.001696
          WForm::resolveLabel270.003620.001737
          CLogger::getLogs320.003550.00355
          BootInput::init340.0032610.003261
          CWebUser::getIsGuest200.0032580.000518
          YiiBase::createComponent20.0032530.000316
          WForm::textField10.0032446.1E-5
          CActiveForm::hiddenField40.0031780.000103
          CWebUser::getState390.0031320.003132
          CHtml::activeHiddenField40.0030750.000293
          WForm::dropDownList10.003054.9E-5
          CActiveRecord::getAttributeLabel430.0030.003
          CHtml::checkBox30.0029530.000686
          CHtml::resolveName430.002940.00294
          AccessManager::_getUserRole20.0024688.8E-5
          CMysqlSchema::createColumn40.0024140.000723
          WebUser::getDefaultRoleContexts100.0022690.000245
          CDbCommandBuilder::createFindCommand20.0020990.000552
          WebUser::getAllowedRoles100.0020240.000743
          CWidget::__construct340.0019520.001952
          CDbColumnSchema::init50.0017980.000444
          CComponent::__isset200.0016120.001612
          BootActiveForm::init10.0011776.9E-5
          CList::insertAt210.0011170.001117
          CActiveForm::init10.0011084.6E-5
          CHtml::beginForm10.0009970.000139
          WebUser::getDefaultRole100.0009020.000247
          CHtml::normalizeUrl10.0008586.8E-5
          CMysqlColumnSchema::extractLimit50.0007960.000165
          CDbCommand::prepare60.0006790.000385
          CDbColumnSchema::extractLimit50.0006310.000631
          ValidationRule::afterFind20.0006126.0E-5
          CDbCommand::setText40.0005140.000267
          CDbCommand::bindValue20.0005080.000105
          CDbCriteria::compare20.0005010.000357
          CActiveRecord::getPrimaryKey20.0003280.000189
          call_user_func20.0003285.5E-5
          CActiveRecord::applyScopes20.0003130.000134
          CMysqlColumnSchema::extractType50.0003110.000311
          CDbSchema::quoteColumnName50.0002830.000283
          MyModel::getReferenceName20.0002736.3E-5
          CDbConnection::setActive40.0002720.000272
          CComponent::hasEventHandler40.0002630.000263
          CDbCommand::cancel40.0002470.000247
          CMysqlColumnSchema::extractDefault20.0002475.7E-5
          CApplicationComponent::init20.0002199.3E-5
          CComponent::__set20.0002130.000108
          CDbCommandBuilder::applyLimit20.0001960.000196
          ActiveRecord::init20.0001955.9E-5
          CActiveRecord::beforeFind20.0001915.4E-5
          CDbColumnSchema::extractDefault20.000199.6E-5
          CActiveRecord::afterFind20.0001835.7E-5
          CActiveRecord::getDbCriteria20.0001790.000179
          CComponent::attachBehaviors30.0001780.000178
          CActiveRecord::setAttribute20.0001690.000169
          CDbCommandBuilder::ensureTable20.0001570.000157
          CWidgetFactory::init10.0001514.2E-5
          CDbCriteria::addCondition20.0001440.000144
          ActiveRecord::attachEvents20.0001360.000136
          CDbCommandBuilder::createCriteria20.0001320.000132
          CList::__construct10.000127.2E-5
          CDbConnection::getPdoType20.0001190.000119
          CModel::setScenario20.0001160.000116
          CMysqlSchema::resolveTableNames10.0001090.000109
          usort10.0001042.2E-5
          CHttpRequest::getUrl19.8E-52.5E-5
          CDbColumnSchema::typecast19.4E-59.4E-5
          {closure}18.2E-58.2E-5
          CHttpRequest::getRequestUri17.3E-57.3E-5
          YiiBase::setPathOfAlias16.4E-56.4E-5
          CDbCriteria::__construct16.1E-56.1E-5
          uniqueMultiColumnValidator::setCaseSensitiveAttr15.5E-55.5E-5
          CWidget::setId15.0E-55.0E-5
          CList::setReadOnly14.8E-54.8E-5
           0.649763
        Changelog:
        • v2.3
        profileEnd([string $name = null])

        Stops recording profile info & adds info to the log

        • if name is passed and it matches the name of a profile being recorded, then that profile is stopped.
        • if name is passed and it does not match the name of a profile being recorded, nothing will be done
        • if name is not passed, the most recently started profile is stopped (named, or non-named).

        Parameters

        $name
        Optional Profile name
        Example Source
        /*
            enablePofiling must be set before files containing code to be profiled are included
            (should be set when instantiating PHPDebugConsole)
        */
        $debug->setCfg('enableProfiling', true);
        $debug->profile();
        // build a html form
        //    this is real-world.  guess the framework
        //    how many classes and calls does it take to build a form?!
        // ...
        $debug->profileEnd();
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • Profile 'Profile 1' started
        • Profile 'Profile 1' Results
           callstotalTimeownTime
          CBaseController::beginWidget10.6497570.016487
          CModule::__get350.3743570.001115
          BootActiveForm::inputRow340.3723180.002285
          BootInput::run340.3495550.005287
          CModel::getValidators1310.3051930.087937
          CHtml::openTag340.2728060.001669
          BootInput::getLabel270.243550.001747
          BootActiveForm::dropDownListRow80.1663880.000251
          CListIterator::next28510.1620770.162077
          CModel::isAttributeRequired730.1589480.005975
          BootActiveForm::textFieldRow180.1587010.000439
          CActiveForm::dropDownList90.1197840.000368
          CHtml::activeDropDownList90.1168680.00125
          CHtml::tag3720.1145030.012069
          CHtml::resolveValue400.1118830.026433
          CHtml::renderAttributes4090.1112580.111258
          CActiveForm::textField190.0733670.000563
          CHtml::activeTextField190.0671020.00162
          CHtml::activeInputField230.0613790.004848
          WForm::label270.0490110.002613
          CModel::createValidators10.0414180.000133
          BootActiveForm::checkBoxRow70.0406090.000235
          buildCustField30.0374630.001219
          AppSettingManager::get40.0313540.000555
          MyModel::rules10.0310990.000325
          WForm::resolveArgs480.027970.010955
          ValidationRule::model10.0256956.5E-5
          YiiBase::log160.0250590.004995
          CList::getIterator1510.0221660.005364
          CLogger::log160.0200650.002577
          CComponent::__get350.0194560.002591
          CDbCommand::getText160.0191840.00109
          WForm::checkBox70.0189220.000215
          CActiveForm::label270.0181920.001984
          CActiveRecord::model10.0178529.1E-5
          CLogger::flush160.0174880.001229
          CListIterator::__construct1510.0168020.016802
          AccessManager::isAllowed20.0167740.000702
          include180.0164720.010252
          CEvent::__construct160.0162590.001548
          CHtml::activeLabel270.0162080.004621
          CActiveRecordMetaData::__construct10.0161780.000325
          CActiveForm::checkBox70.0158750.000245
          CDbSchema::getTable10.0158530.000114
          CMysqlSchema::loadTable10.0157396.8E-5
          CMysqlSchema::findColumns10.0155620.000515
          CActiveRecord::query20.0151920.000198
          WForm::resolveName990.0147460.014746
          CComponent::raiseEvent160.0147110.00158
          CDbConnection::createCommand40.0138270.000416
          CWidgetFactory::createWidget340.0136040.009948
          CDbCommand::queryRow20.0123910.000661
          CDbCommand::__construct40.0122410.001517
          CModule::getComponent20.0117870.000314
          AccessRole::isAllowed100.011730.000417
          CHtml::label270.0115870.003098
          SAML2_autoload80.0114580.00304
          BootActiveForm::error340.0108590.006517
          CHtml::activeCheckBox70.010530.000966
          CDbCommand::queryInternal20.0104790.001404
          ValidationRuleManager::findOptionsByModel10.0102833.9E-5
          CValidator::createValidator200.0100670.004505
          WForm::hiddenField40.0095780.000119
          CLogRouter::collectLogs160.0095280.003129
          CActiveRecord::find10.009266.0E-5
          spl_autoload_call60.0090630.000206
          YiiBase::import100.0088990.001484
          CBaseController::createWidget10.0088952.8E-5
          CHtml::hiddenField80.0084330.000782
          WForm::resolveModel560.0078340.007834
          CWebApplication::getWidgetFactory10.007699.8E-5
          BootActiveForm::checkBoxListRow10.0075692.4E-5
          YiiBase::autoload80.007520.000231
          WebUser::__get120.0073430.000347
          CLogRoute::collectLogs320.0063990.00285
          AccessRule::match100.0063490.002645
          WForm::resolveAttribute1010.0059550.005955
          CHtml::inputField110.0058290.001498
          CHtml::resolveNameID400.0056240.005476
          YiiBase::trace30.0055790.000144
          WebUser::_getModel200.005440.00057
          CWebUser::__get200.005260.000473
          ActiveRecord::__get650.0052290.004732
          BootActiveForm::checkBoxList10.0051453.3E-5
          WebUser::getState390.0050630.001931
          CWebUser::hasState200.0047870.001617
          BootActiveForm::inputsList10.0044150.000679
          BootActiveForm::getErrorHtml340.0043420.002017
          AppSettingManager::arrayPath180.0043080.004308
          YiiBase::getPathOfAlias30.003930.001696
          WForm::resolveLabel270.003620.001737
          CLogger::getLogs320.003550.00355
          BootInput::init340.0032610.003261
          CWebUser::getIsGuest200.0032580.000518
          YiiBase::createComponent20.0032530.000316
          WForm::textField10.0032446.1E-5
          CActiveForm::hiddenField40.0031780.000103
          CWebUser::getState390.0031320.003132
          CHtml::activeHiddenField40.0030750.000293
          WForm::dropDownList10.003054.9E-5
          CActiveRecord::getAttributeLabel430.0030.003
          CHtml::checkBox30.0029530.000686
          CHtml::resolveName430.002940.00294
          AccessManager::_getUserRole20.0024688.8E-5
          CMysqlSchema::createColumn40.0024140.000723
          WebUser::getDefaultRoleContexts100.0022690.000245
          CDbCommandBuilder::createFindCommand20.0020990.000552
          WebUser::getAllowedRoles100.0020240.000743
          CWidget::__construct340.0019520.001952
          CDbColumnSchema::init50.0017980.000444
          CComponent::__isset200.0016120.001612
          BootActiveForm::init10.0011776.9E-5
          CList::insertAt210.0011170.001117
          CActiveForm::init10.0011084.6E-5
          CHtml::beginForm10.0009970.000139
          WebUser::getDefaultRole100.0009020.000247
          CHtml::normalizeUrl10.0008586.8E-5
          CMysqlColumnSchema::extractLimit50.0007960.000165
          CDbCommand::prepare60.0006790.000385
          CDbColumnSchema::extractLimit50.0006310.000631
          ValidationRule::afterFind20.0006126.0E-5
          CDbCommand::setText40.0005140.000267
          CDbCommand::bindValue20.0005080.000105
          CDbCriteria::compare20.0005010.000357
          CActiveRecord::getPrimaryKey20.0003280.000189
          call_user_func20.0003285.5E-5
          CActiveRecord::applyScopes20.0003130.000134
          CMysqlColumnSchema::extractType50.0003110.000311
          CDbSchema::quoteColumnName50.0002830.000283
          MyModel::getReferenceName20.0002736.3E-5
          CDbConnection::setActive40.0002720.000272
          CComponent::hasEventHandler40.0002630.000263
          CDbCommand::cancel40.0002470.000247
          CMysqlColumnSchema::extractDefault20.0002475.7E-5
          CApplicationComponent::init20.0002199.3E-5
          CComponent::__set20.0002130.000108
          CDbCommandBuilder::applyLimit20.0001960.000196
          ActiveRecord::init20.0001955.9E-5
          CActiveRecord::beforeFind20.0001915.4E-5
          CDbColumnSchema::extractDefault20.000199.6E-5
          CActiveRecord::afterFind20.0001835.7E-5
          CActiveRecord::getDbCriteria20.0001790.000179
          CComponent::attachBehaviors30.0001780.000178
          CActiveRecord::setAttribute20.0001690.000169
          CDbCommandBuilder::ensureTable20.0001570.000157
          CWidgetFactory::init10.0001514.2E-5
          CDbCriteria::addCondition20.0001440.000144
          ActiveRecord::attachEvents20.0001360.000136
          CDbCommandBuilder::createCriteria20.0001320.000132
          CList::__construct10.000127.2E-5
          CDbConnection::getPdoType20.0001190.000119
          CModel::setScenario20.0001160.000116
          CMysqlSchema::resolveTableNames10.0001090.000109
          usort10.0001042.2E-5
          CHttpRequest::getUrl19.8E-52.5E-5
          CDbColumnSchema::typecast19.4E-59.4E-5
          {closure}18.2E-58.2E-5
          CHttpRequest::getRequestUri17.3E-57.3E-5
          YiiBase::setPathOfAlias16.4E-56.4E-5
          CDbCriteria::__construct16.1E-56.1E-5
          uniqueMultiColumnValidator::setCaseSensitiveAttr15.5E-55.5E-5
          CWidget::setId15.0E-55.0E-5
          CList::setReadOnly14.8E-54.8E-5
           0.649763
        Changelog:
        • v2.3
        table([mixed ...$arg = ])

        Output array or object as a table

        Parameters

        Takes up to 3 arguments which may be passed in arbitrary order

        • The first encountered array (or Traversable object) is the table data.
        • The first encountered string 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
        Meta options
        totalCols (array) columns that should be summed
        sortable (true) should table be sortable by clicking on headers?
        Example Source
        $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);
        $debug->table(array(
            'foo' => 'bar',
            'slim' => 'jim',
        ));
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 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
            )
          )
        •  value
          foobar
          slimjim

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

        Changelog:
        • v2.1: properly handles Traversable as param
        • v2.0: properly handles array of objects (objects can implement Traversable)
        time([string $label = null[, float $duration = null]])

        Start a timer identified by label

        Label passed

        • if doesn't exist: starts timer
        • if does exist: unpauses (does not reset)

        Label not passed

        • timer will be added to a no-label stack

        Does not append log (unless duration is passed).

        Use timeEnd or timeGet to get time

        Parameters

        $label
        unique label
        $duration
        (optional) duration (in seconds). Use this param to log a duration obtained externally.
        Example Source
        $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'); // no change... timer not running
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • time: 156.8794 μs
        • timer a: 650.8827 μs
        • time: 651.8364 μs
        • timer a: 650.8827 μs
        Changelog:
        • v3.0: duration argument added
        timeEnd([string $label = null[, bool $log = true]])

        Behaves like a stopwatch.. logs and returns running time

        Parameters

        $label
        (optional) unique label
        $log
        (true) log it, or return only
        if passed, takes precedence over silent meta val

        Return Value

        float|false
        The duration (in sec).

        Meta options

        precision
        (4) how many decimal places
        silent
        (false) only return / don't log
        template
        '%label: %time'
        unit
        ('auto'), 'sec', 'ms', or 'us'
        • 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
        Example Source
        $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'); // no change... timer not running
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 2 MB / redacted MB
        • time: 156.8794 μs
        • timer a: 650.8827 μs
        • time: 651.8364 μs
        • timer a: 650.8827 μs
        Changelog:
        • v3.0: returnOrTemplate & precision arguments removed.
          New meta options: precision, silent, template, & unit
        timeGet([string $label = null[, bool $log = true]])

        Log/get the running time without stopping/pausing the timer

        Parameters

        $label
        (optional) unique label
        $log
        (true) log it, or return only
        if passed, takes precedence over silent meta val

        Return Value

        float|false
        The duration (in sec). false if specified label does not exist

        Meta options

        precision
        (4) how many decimal places
        silent
        (false) only return / don't log
        template
        '%label: %time'
        unit
        ('auto'), 'sec', 'ms', or 'us'
        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;
        }
        Example Output
        • Built In 187.427 ms
        • Peak Memory Usage ?⃝: 4 MB / redacted MB
        • queryDb(INSERT INTO student (id, name, age) VALUES ("1", "alan", 28))
          • queryDb(SELECT * FROM student ORDER BY age)
            • query db: 343.0843 μs
            Changelog:
            • v3.0: returnOrTemplate & precision arguments removed.
              New meta options: precision, silent, template, & unit
            timeLog([string $label = null[, mixed ...$args = null]])

            Logs the current value of a timer that was previously started via time()

            also logs additional arguments

            Parameters

            $label
            (optional) unique label
            ...$args
            (optional) additional values to be logged with time
            Example Source
            $debug->time('timer a');
            usleep(100);
            $debug->timeLog('timer a', 'foo', array('foo'=>'bar'));
            usleep(100);
            $debug->log('other things happen');
            // always logs time since timer last started/unpaused
            $debug->timeLog('timer a', 'bar', array('bar'=>'baz'));
            Example Output
            • Built In 187.427 ms
            • Peak Memory Usage ?⃝: 4 MB / redacted MB
            • timer a: 788.9271 μs, foo, array(
              • foo=>bar
              )
            • other things happen
            • timer a: 1.0068 ms, bar, array(
              • bar=>baz
              )
            Changelog:
            • v2.3
            trace([bool $inclContext = false[, string $caption = trace]])

            Log a stack trace

            Essentially PHP's debug_backtrace(), but displayed as a table

            Parameters

            $inclContext
            Include code snippet
            $caption
            (optional) Specify caption for the trace table
            Example Source
            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');
            Example Output
            • Built In 187.427 ms
            • Peak Memory Usage ?⃝: 4 MB / redacted MB
            • trace
               filelinefunction
              0/path/to/mypage.inc.php111
              1/path/to/mypage.inc.php111{closure}
              2/path/to/mypage.inc.php111func2
              3/path/to/mypage.inc.php111func1
            • sorting is disabled for trace tables
            warn([mixed ...$arg = ])

            Log a warning

            Parameters

            ...$arg
            message / values
            Example Source
            $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');
            Example Output
            • Built In 187.427 ms
            • Peak Memory Usage ?⃝: 2 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
            Changelog:
            • v3.0: first param now gets htmlspecialchar()'d by default
              use meta('sanitizeFirst', false) to allow html

            Config & Utility methods

            addPlugin(AssetProviderInterface|SubscriberInterface $plugin)

            Extend debug with a plugin

            Parameters

            $plugin
            object implementing SubscriberInterface and/or AssetProviderInterface

            Return Value

            $this
            getChannel(string $name[, array $config = array()])

            Return a named subinstance... if channel does not exist, it will be created

            Parameters

            $name
            channel name
            $config
            channel specific configuration

            Return Value

            static
            new or existing Debug instance
            • Initial config inherited from parent
            • HTML output: channel toggle checkboxes will be available if more than one channel is output
            • Channels get a new eventManager instance\bdk\Debug::EVENT_LOG, \bdk\Debug::EVENT_OBJ_ABSTRACT_START, and \bdk\Debug::EVENT_OBJ_ABSTRACT_END events "bubble" up ancestor channels.
            Example Source
            $seinfeld = $debug->getChannel('seinfeld');
            $debug->log('This is Unix. I know this!');
            $seinfeld->log('I always wanted to pretend I was an architect');
            $debug->info('note that log entries nested inside a different channel\'s groups will not be hidden when the parent channel is hidden');
            $seinfeld->group('The Bizarro Jerry');
                $seinfeld->log('You got a question? You ask the 8-ball.');
                $debug->log('Use SQL to corrupt their databases.');
            $seinfeld->groupEnd();
            $debug->group('Swordfish');
                $seinfeld->log('just remember, it\'s not a lie if you believe it.');
                $debug->log('Where I can hook up my modem?');
            $debug->groupEnd();
            Example Output
            • The above channel toggles are rendered much more attractively in the full debug output. See the main example attached to bottom of viewport
            • Built In 187.427 ms
            • Peak Memory Usage ?⃝: 4 MB / redacted MB
            • This is Unix. I know this!
            • I always wanted to pretend I was an architect
            • note that log entries nested inside a different channel's groups will not be hidden when the parent channel is hidden
            • The Bizarro Jerry
              • You got a question? You ask the 8-ball.
              • Use SQL to corrupt their databases.
            • Swordfish
              • just remember, it's not a lie if you believe it.
              • Where I can hook up my modem?
            Changelog:
            • v2.3
            getCfg([string $path = null[, null|string $opt = null]])

            Retrieve a configuration value

            Parameters

            $path
            what to get
            $opt
            (@internal)

            Return Value

            mixed
            value
            Example Source
            $debug->log('output', $debug->getCfg('output'));
            $debug->log('route', $debug->getCfg('route'));
            $debug->log('errorEmailer.emailMin', $debug->getCfg('errorEmailer.emailMin'));
            Example Output
            • Built In 187.427 ms
            • Peak Memory Usage ?⃝: 4 MB / redacted MB
            • output = true
            • route = html
            • errorEmailer.emailMin = 60
            getHeaders()

            Get and clear headers that need to be output

            Return Value

            array
            headerName=>value array

            By default, response headers (ie generated by chromeLogger or FirePHP) are automatically set.

            When working with frameworks or a PSR-7 implementation, you may want to deal with headers differently.

            To use this method:

            • set outputHeaders = false. This will prevent headers from being set automatically
            • After output(), you can call getHeaders()
            Example Source
            $debug = new \bdk\Debug(array(
                // use collect/output combo or key
                'collect' => true,  // turn logging on
                'output' => true,   // output() should process / return the log
                'route' => 'chromeLogger',
                'outputHeaders' => false, // we'll need to deal with headers manually
            ));
            /*
                either call output() manually and then call getHeaders()
                or, subscribe to debug.output (as we're doing here) with a low priority
                (needs to execute after other subscribers so that headers have been created)
                and get the headers from within the subscriber
            */
            $debug->eventManager->subscribe('debug.output', function(\bdk\PubSub\Event $event) {
                $debug = $event->getSubject();
                $headers = $debug->getHeaders(); // get and clear headers
                // var dumping headers for example... debug already output
                var_dump($headers);
                foreach ($headers as $nameAndValue) {
                    header($nameAndValue[0].': '.$nameAndValue[1]);
                }
            }, -1);
            
            $debug->log('hello world');
            Example Output
            array(1) {
              [0]=> array(2) {
                [0]=> string(19) "X-ChromeLogger-Data"
                [1]=> string(328) "eyJ2ZXJzaW9uIjoiMy4wIiwiY29sdW1ucyI6WyJsb2ciLCJiYWNrdHJhY2UiLCJ0eXBlIl0sInJvd3MiOltbWyJQSFAiLCJQT1NUIC9teUZvcm0iXSxudWxsLCJncm91cENvbGxhcHNlZCJdLFtbIkJ1aWx0IEluIDE4Ny40MjcgbXMiXSxudWxsLCJpbmZvIl0sW1siUGVhayBNZW1vcnkgVXNhZ2U6IDQgTUIgLyAyIEdCIl0sbnVsbCwiaW5mbyJdLFtbImhlbGxvIHdvcmxkIl0sbnVsbCwiIl0sW1tdLG51bGwsImdyb3VwRW5kIl1dfQ=="
              }
            }
            
            Changelog:
            • v2.3
            static meta([mixed ...$args = ])

            "metafy" value/values

            Accepts:

            • meta(array $values)
            • meta(string $key[, mixed $value = true])
            • meta(cfg, array $values)
            • meta(cfg, string $cfgKey[, mixed $cfgValue = true])

            This "utility" method can be used to pass "meta" or config information to methods

            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

            Example usage:

            • Create a group that will be hidden (as opposed to collapsed) if empty
            • Specifying (overriding) the file & line of error/warn
            • Specifying custom icon, css-class, or style
            • Setting a config value for a single call
            Universal options
            attribs (array) Html attributes to apply to the log entry
            detectFiles (false) detect if strings are filepaths... for creation of editor/IDE links
            icon (null) classname(s) for custom icon (ie fa fa-hand-lizard-o)
            redact (false) Redact strings (see redactKeys)
            sanitize (true) Whether to pass html output through htmlspecialchars()
            sanitizeFirst (defaults to sanitize value) Whether to pass first argument through htmlspecialchars()
            Specifying that the group should be hidden if it's empty:
            $debug->group('group label', $debug->meta('hideIfEmpty'));
            Specify that the object's methods should not be collected for this call
            $debug->log('my object', $myObject, $debug->meta('cfg', 'collectMethods', false));
            // or
            $debug->log('my object', $myObject, $debug->meta('cfg', array('collectMethods' => false)));
            // or
            $debug->log('my object', $myObject, $debug->meta(array('cfg' => array('collectMethods' => false))));
            output([array $cfg = array()])

            Return debug log output

            Parameters

            $cfg
            Override any config values

            Return Value

            string|null

            Publishes Debug::EVENT_OUTPUT event and returns event's 'return' value

            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)
            Example Source
            // 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 null
            ));
            $debug->log('hello world');
            echo $debug->output();
            Example Output
            • Built In 187.427 ms
            • Peak Memory Usage ?⃝: 4 MB / redacted MB
            • hello world
            Changelog:
            • v2.3: $config parameter
            • v1.2: explicitly calling output() is no longer necessary.. log will be output automatically via shutdown function
            removePlugin(SubscriberInterface $plugin)

            Remove plugin

            Parameters

            $plugin
            object implementing SubscriberInterface

            Return Value

            $this
            setCfg(string|array $path[, mixed $value = null])

            Set one or more config values

            setCfg('key', 'value')
            setCfg('level1.level2', 'value')
            setCfg(array('k1'=>'v1', 'k2'=>'v2'))

            Parameters

            $path
            path
            $value
            value

            Return Value

            mixed
            previous value(s)
            Example Source
            $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,
                ),
            ));
            Example Output
            • Built In 187.427 ms
            • Peak Memory Usage ?⃝: 4 MB / redacted MB
              setErrorCaller([array $caller = null])

              A wrapper for errorHandler->setErrorCaller

              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()

              Example Source
              trustyOldFunction();
              
              /*
                  PHP's 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);
              }
              Example Output
              • Built In 187.427 ms
              • Peak Memory Usage ?⃝: 4 MB / redacted MB
              • User Deprecated: trustyOldFunction's days are numbered. Use superNewFunction instead., /path/to/mypage.inc.php (line 1)
              • lastError =
                bdk\ErrorHandler\Error
                extends
                bdk\PubSub\Event
                implements
                ArrayAccess
                IteratorAggregate
                Traversable
                constants
                public CAT_DEPRECATED = deprecated
                public CAT_ERROR = error
                public CAT_FATAL = fatal
                public CAT_NOTICE = notice
                public CAT_STRICT = strict
                public CAT_WARNING = warning
                properties (via __debugInfo)
                protected array|false|null backtrace = null
                protected static errCategories = array(
                • deprecated=>array(
                  • 0=>8192
                  • 1=>16384
                  )
                • error=>array(
                  • 0=>256
                  • 1=>4096
                  )
                • notice=>array(
                  • 0=>8
                  • 1=>1024
                  )
                • strict=>array(
                  • 0=>2048
                  )
                • warning=>array(
                  • 0=>2
                  • 1=>32
                  • 2=>128
                  • 3=>512
                  )
                • fatal=>array(
                  • 0=>1
                  • 1=>4
                  • 2=>64
                  • 3=>16
                  )
                )
                protected static errTypes = array(
                • 1=>Fatal Error
                • 2=>Warning
                • 4=>Parsing Error
                • 8=>Notice
                • 16=>Core Error
                • 32=>Core Warning
                • 64=>Compile Error
                • 128=>Compile Warning
                • 256=>User Error
                • 512=>User Warning
                • 1024=>User Notice
                • 32767=>E_ALL
                • 2048=>Runtime Notice (E_STRICT)
                • 4096=>Recoverable Error
                • 8192=>Deprecated
                • 16384=>User Deprecated
                )
                protected mixed subject = bdk\ErrorHandler
                protected static userErrors = array(
                • 0=>16384
                • 1=>256
                • 2=>1024
                • 3=>512
                )
                protected array values = 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
                  )
                • continueToNormal=>false
                • continueToPrevHandler=>true
                • exception=>null
                • hash=>58e34d9b4cefc0f95d2672453b806fe5
                • isFirstOccur=>true
                • isHtml=>false
                • isSuppressed=>false
                • throw=>false
                • email=>false
                • stats=>array(
                  • tsEmailed=>0
                  • countSince=>0
                  • emailedTo=>
                  )
                • inConsole=>true
                )
                private (bdk\PubSub\Event) bool propagationStopped = true
                magic array context
                magic array trace
                methods
                public __construct(ErrorHandler $errHandler, int $errType, string $errMsg, string $file, string $line, array $vars = array())
                public array __debugInfo()
                public \Exception|\ErrorException asException()
                public ArrayIterator getIterator()
                public string getMessage()
                public mixed getSubject()
                public array|false|null getTrace(bool|'auto' $withContext = auto)
                public mixed getValue(string $key)
                public array getValues()
                public bool hasValue(string $key)
                public bool isFatal()
                public bool isPropagationStopped()
                public bool log()
                public bool offsetExists(string $key)
                public mixed offsetGet(string $key)
                public void offsetSet(string $key, mixed $value)
                public void offsetUnset(string $key)
                public $this setValue(string $key, mixed $value)
                public $this setValues(array $values = array())
                public void stopPropagation()
                protected string errorHash()
                protected static string|null getCategory(int $errType)
                protected void onSet()
                private bool isHtml()
                private bool isSuppressed(int $errType, isSuppressed|null $prevOccurance = null)
                private bool setContinueToNormal(int $errType, bool $continueToNormal)
              writeToResponse(ResponseInterface|HttpFoundationResponse $response)

              Appends debug output (if applicable) and/or adds headers (if applicable)

              You should call this at the end of the request/response cycle in your PSR-7 project,
              e.g. immediately before emitting the Response.

              Parameters

              $response
              PSR-7 or HttpFoundation response

              Return Value

              ResponseInterface|HttpFoundationResponse
              See Also: Middleware

              Configuration / Options

              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');
              general options
              channels

              array()

              Provide configuration for yet-to-be-created channels

              example:

              array(
                  'channelName' => array(
                      'channelIcon' => 'fa fa-bolt',
                  )
              )
              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

              emailFrom

              null

              Specify From address

              If non-null, will be passed to emailFunc in $additionalHeaders param.

              PHP's mail() will default to value defined to php.ini's sendmail_from value

              emailFunc

              email

              A callable that receives 4 parameters: $to, $subject, $body, & string $additionalHeaders

              emailLog

              false

              Whether to email a debug log.

              Values may be:
              • false - log not sent
              • 'onError' log sent if there was an error masked by the errorHandler.emailMask config value
              • true (or 'always') - log always sent (if not being output)

              See email route for more information

              requires collect to also be true
              (we can't email what we don't collect)

              ChangeLog:

              v3.0: true is now synonymous with "always" (was "onError")
              emailTo

              $_SERVER['SERVER_ADMIN']

              Specify where to email logs and error reports

              enableProfiling

              false

              If you will be using profile()/profileEnd() methods, you should set this to true as early as possible.

              PHPDebugConsole will only be able to profile methods/functions that have been included/loaded after this has been set to true.

              Under the hood: profile() works via PHP's register_tick_function(). This function requires a declare(ticks=1) statement in each file with code that will potentially be profiled… To "get around" this requirement, PHPDebugConsole will register a stream wrapper (if/when both collect = true and enableProfiling = true). This streamWrapper will inject declare(ticks=1) on-the-fly. This is done when reading the files - no modification will be written.

              See this "how to natively profile scripts" question on stackOverflow

              ChangeLog:

              v2.3: introduced
              headerMaxAll

              250000

              Maximum size of all headers combined. (Chrome has a limit of 256KB)

              ChangeLog:

              v3.0
              headerMaxPer

              null

              If defined, the maximum size any individual header should be.

              Primarily for ChromeLogger… behind a proxy/load-balancer.

              Many proxies/load-balancers have a hard limit on header size and may throw a 500 error if they receive a large header.

              If you run into an issue, try setting this value to "16K", "8K", "8000", etc

              ChangeLog:

              v3.0
              key

              null

              Set a "password/key" to enable/view debug info. This key should be passed to the page as a request parameter ($_GET['debug'] or $_COOKIE['debug']).

              Example:
              key set to to "bosco":
              • If we visit our page with the correct 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

              ChangeLog:

              • v3.0: No effect for scripts called from the command line
              logEnvInfo
              array(
                  'errorReporting' => true, // notice if not `E_ALL | E_STRICT`
                  'files' => true,          // files included during request
                  'gitInfo' => true,        // git branch if applicable
                  'phpInfo' => true,        // PHP_VERSION, memoryLimit, etc
                  'serverVals' => true,     // $_SERVER values specified by logServerKeys
                  'session' => true,        // session data
              )

              Specify "environment" information to automatically log.

              Also accepts true (all), or false (none).

              Example
              Example Source
              $debug = new \bdk\Debug(array(
              	'collect' => true,
              	'output' => true,
              	'logEnvInfo' => true, // this is the default (all other examples use `false`)
              ));
              $debug->log('This example includes example values');
              $debug->info('Not all $_SERVER values are output -> only those included in `logServerKeys');
              Example Output
              • git branch: master
              • Built In 187.427 ms
              • Peak Memory Usage ?⃝: 4 MB / redacted MB
              • This example includes example values
              • Not all $_SERVER values are output -> only those included in `logServerKeys
                • PHP Version = 7.4.13
                • ini files = array(
                  • /path/to/php.ini
                  • /usr/local/etc/php/7.4/conf.d/ext-opcache.ini
                  )
                • date.timezone = America/Chicago
                • memory_limit = redacted MB
                • Xdebug is not installed
                • $_SERVER = array(
                  • CONTENT_LENGTH=>35
                  • CONTENT_TYPE=>application/x-www-form-urlencoded
                  • REMOTE_ADDR=>
                  • REQUEST_METHOD=>POST
                  • REQUEST_TIME=>
                  • REQUEST_URI=>/myForm
                  • SERVER_ADDR=>
                  • SERVER_NAME=>
                  )
                  • session.cookie_httponly should be enabled
                  • session.cache_limiter = nocache
                  • session save_path = /var/tmp/
                  • session name = SESSIONID
                  • session id = e8ur1fvnbp26fj4ganpadbf3dd
                  • $_SESSION = array()

                  ChangeLog:

                  • v3.0: errorReporting, gitInfo, & session added
                    cookies, headers, & post removed (moved to logRequestInfo)
                  • v2.3: accepts array in addition to boolean
                  • v2.0: introduced
                  logRequestInfo
                  array(
                      'cookies' => true,
                      'files' => true,   // $_FILES
                      'headers' => true, // request headers
                      'post' => true,    // $_POST (or request body)
                  )

                  Specify request information to automatically log.

                  Also accepts true (all), or false (none).

                  Example
                  Example Source
                  $debug = new \bdk\Debug(array(
                  	'collect' => true,
                  	'output' => true,
                  	'logRequestInfo' => true, // this is the default (all other examples use `false`),
                  	'logResponse' => true, // this is the default (other other examples use `false`),
                  ));
                  $debug->log('This example includes example values');
                  Example Output
                    • request headers
                       value
                      Accepttext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
                      Accept-Encodingbr,gzip
                      Accept-Languageen-US,en;q=0.5
                      Connectionclose
                      Content-Length35
                      Content-Typeapplication/x-www-form-urlencoded
                      CookieSESSIONID=5umr2d3e392f6idhvpadiqs7r0; =
                      Hostwww.bradkent.com
                      If-Modified-SinceFri, 22 Jan 2021 02:35:04 GMT
                      User-AgentCCBot/2.0 (https://commoncrawl.org/faq/)
                    • $_COOKIE
                       value
                      SESSIONID5umr2d3e392f6idhvpadiqs7r0
                    • $_POST = array(
                      • username=>superman
                      • password=>█████████
                      )
                    • response headers
                       value
                      Content-Typetext/html
                      CookieSESSIONID=5umr2d3e392f6idhvpadiqs7r0
                    • Not logging response body for Content-Type "text/html"
                    • Built In 187.427 ms
                    • Peak Memory Usage ?⃝: 4 MB / redacted MB
                    • This example includes example values

                            ChangeLog:

                            v3.0
                            logResponse

                            auto

                            Whether to begin buffering output & potentialy log response

                            auto
                            (default) We will begin buffering output if ajax request, have SoapAction header, or have a Accepts header that does not contain "html"
                            true
                            Begin buffering output
                            false
                            Don't buffer output. Response will not be logged

                            If output is being buffered, we will log the output upon shutdown if response Content-Type is json or xml.

                            See also writeToResponse()

                            ChangeLog:

                            v3.0
                            logResponseMaxLen

                            1 MB

                            Set a size limit to logging response

                            If size is exceeded, response will not be output

                            integer or string

                            0 / null : No Limit

                            logRuntime

                            true

                            Log script duration and memory usage.

                            ChangeLog:

                            v3.0
                            logServerKeys

                            array("REMOTE_ADDR","REQUEST_TIME","REQUEST_URI","SERVER_ADDR","SERVER_NAME")

                            Specified $_SERVER values will be logged if logEnvInfo.serverVals == true

                            • HTTP_HOST will be included if logEnvInfo doesn't include "headers"
                            • CONTENT_LENGTH & CONTENT_TYPE will be included if applicable
                            • REQUEST_METHOD will be included if REQUEST_METHOD != 'GET'

                            ChangeLog:

                            v2.0: introduced
                            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:

                            v2.0: introduced
                            onLog

                            null

                            • A callable to be called before entry added to log.
                            • Callback will receive a single param: \bdk\PubSub\Event $event.
                            • Shortcut for subscribing to \bdk\Debug::EVENT_LOG event

                            ChangeLog:

                            • v2.0: introduced
                            • v2.0.1: replaces previous onLog value (rather than add additional subscriber)
                            onMiddleware

                            null

                            • A Callable to be called before our middleware writes to response
                            • Callback will receive a single param: \bdk\PubSub\Event $event. Event object contains request and response objects
                            • Shortcut for subscribing to \bdk\Debug::EVENT_MIDDLEWARE event.

                            ChangeLog:

                            • v3.0: introduced
                            onOutput

                            null

                            • A callable to be called before log is output.
                            • Callback will receive a single param: \bdk\PubSub\Event $event.
                            • Shortcut for subscribing to \bdk\Debug::EVENT_OUTPUT event.
                            • Given default subscriber priority of 0 (will get called before log is output)
                            • Able to modify log, but not do post-output actions such as getHeaders()

                            ChangeLog:

                            • v2.0: passed param changed from (string) $outputAs to \bdk\PubSub\Event
                            • v2.0.1: replaces previous onOutput value (rather than add additional subscriber) (this is the pre v2.0 behavior)
                            output

                            false

                            Should output() actually output the log?

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

                            redactKeys

                            array("password")

                            A list of keys that should be redacted when redact meta option is passed.

                            Keys will also be found and redacted in url-encoded strings, xml, & json

                            The string (or portion thereof) that needs redacted will be passed to the callable defined by redactReplace

                            Examples:

                            Perform redaction on xml
                            $debug->log('response', $xml, $debug->meta('redact'));
                            Perform redaction on an array
                            $debug->log('api params', $params, $debug->meta('redact'));
                            • Redaction is not performed on all log entries.
                            • Redcation is only performed when redact meta option is passed.

                            Redaction is performed on out-of-the-box logging of input/$_POST, $_COOKIE, request headers, $_SERVER values, & response

                            ChangeLog:

                            v3.0
                            redactReplace

                            callable

                            A callable that receives the string being redacted and the key

                            Default callable returns "█████████"

                            See also redactKeys

                            ChangeLog:

                            v3.0
                            sessionName

                            null

                            If logging session data (see logEnvInfo), optionally specify session name

                            If not specified, we will try "PHPSESSID" (php's default, but not recommended), "SESSIONID", "SESSION_ID", "SESSID", and "SESS_ID"

                            stream

                            null

                            A valid filepath, stream-url, or resource, to write the log. This will supplement the log that is output via output()

                            ChangeLog:

                            v3.0 replaces "file" option
                            stringMaxLen
                            array(
                                'base64' => 154, // only 1st 154 chars of base-64 string will be shown
                                'binary' => array(
                                    128 => 0,    // if over 128 bytes don't capture / store
                                ),
                                'other' => 8192,
                            )

                            Controls the maximum string length (in bytes) that is collected/shown for string values

                            specifying an int (vs array) will set the "other" value

                            -1 = no maximum

                            ChangeLog:

                            v3.0: introduced
                            stringMinLen
                            array(
                                'contentType' => 256, // try to determine content-type of binary string
                                'encoded' => 16, // test if bas64, json, or serialized (-1 = don't check)
                            )

                            Specify the minimum length of a string before we inspect it to determine the content-type or check if json/base64/serialized

                            ChangeLog:

                            v3.0: introduced
                            output related options

                            These options deal with how the log is output

                            outputHeaders

                            true

                            Should PHPDebugConsole output headers (ie, ChromeLogger & FirePHP headers) on output?

                            By default, PHPDebugConsole performs output at the end of script execution.
                            If your script has already output its body content, it's too late for additional headers.

                            Solutions:

                            • Call ob_start(); at the beginning of your script.. This will buffer all output until the very end
                            • Manually call $debug->output(); before output sent
                              • Manually call $debug->output(); with outputHeaders = false before output sent
                              • Call $debug->getHeaders();, loop over returned array, & manually call header(), or modify your frameworks's response object, etc

                            ChangeLog:

                            • v2.3: introduced
                            route

                            auto

                            • With the default value ("auto"), output "route" will be determined based on request / response
                              • "html" if non-ajax, Content-Type: html is being output
                              • routeNonHtml for other http requests (which defaults to "chromeLogger")
                              • "stream" from command line
                            • Options:

                              chromeLogger
                              • Outputs the log via special http headers.
                              • Requires browser extension to view.
                              • Details
                              email
                              firephp
                              • Outputs the log via special http headers
                              • Requires browser extension to view.
                              • Details
                              html
                              • Outputs the log as HTML, along with css and javascript
                              • Details
                              script
                              • Outputs the log as <script></script> containing console.xxx calls
                              • Details
                              stream
                              • Writes log entries to a file/resource/url specified by the stream option
                              • Details
                              text
                              • Outputs the log as plain text
                              • Details
                              wamp
                              • Sends logging in realtime to a WAMP router
                              • works with ajax, CLI, html, API server, everything
                              • True console-like logging.
                              • "Advanced"
                              • Details
                              OTHER
                              Any object implementing \bdk\Debug\RouteInterface

                            ChangeLog:

                            v3.0 replaces "outputAs" option
                            routeNonHtml

                            chromeLogger

                            If route is "auto", this value will be used for http requests that are ajax or non-html response

                            ChangeLog:

                            v3.0 replaces "outputAsDefaultNonHtml" option
                            html related options
                            css

                            Supplemental CSS to output

                            drawer

                            true

                            Whether to place output in dockable "drawer"?

                            ChangeLog:

                            v3.0
                            filepathCss

                            ./css/Debug.css

                            Filepath to base CSS.

                            • (need not be publicly accessible)
                            filepathScript

                            ./js/Debug.jquery.min.js

                            Filepath to javascript to include.

                            • (need not be publicly accessible)
                            jqueryUrl

                            //ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js

                            Only loaded if window.jQuery is undefined

                            outputCss

                            true

                            Output filepathCss contents with the log?

                            outputScript

                            true

                            Output filepathScript contents with the log?

                            sidebar

                            true

                            Display filter sidebar?

                            ChangeLog:

                            v3.0
                            object logging & output options

                            These options deal specifically with debugging objects

                            cacheMethods

                            true

                            Whether PHPDebugConsole assumes all instances of a given class will have the same methods.

                            The need to disable this is extremely rare

                            ChangeLog:

                            v2.3: introduced
                            collectAttributesConst
                            collectAttributesMethod
                            collectAttributesObj
                            collectAttributesParam
                            collectAttributesProp

                            true

                            Whether to collect Attributes on constants, methods, the object, method params, and properties

                            collectConstants

                            true

                            Whether to collect object constants

                            collectMethods

                            true

                            Whether to collect object methods, return types, parameter information, etc

                            objectsExclude

                            array("bdk\\Debug\\Abstraction","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.

                            Accepts "visibility", "name", or false|null

                            outputAttributesConst
                            outputAttributesMethod
                            outputAttributesObj
                            outputAttributesParam
                            outputAttributesProp

                            true

                            Whether to output collected attributes

                            outputConstants

                            true

                            Whether to output object's constants

                            outputMethodDesc

                            true

                            Whether to output method's long phpDoc description

                            ChangeLog:

                            v3.0: formerly "outputMethodDescription"
                            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 icon .
                            • If the value came exclusively from __debugInfo, it will be listed with "debug" visibility
                            errorEmailer options
                            • configure how error notifications are emailed
                            • errors are only emailed if not captured by debugger (capture=false at time of error)
                            • errorEmailer options may be set via the Debug object for convenience
                            emailMask

                            E_ERROR | E_PARSE | E_COMPILE_ERROR | E_WARNING | E_USER_ERROR | E_USER_NOTICE

                            Specify 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

                            ChangeLog:

                            v3.0 default changed to 60 (was 15)
                            emailThrottledSummary

                            true

                            Whether to send an email summary of throttled errors on trash-collection

                            emailThrottleFile

                            __DIR__ . '/error_emails.json'

                            A file used to maintain details of recently emailed errors.

                            This is the default means of maintaining throttle data.

                            See emailThrottleRead and emailThrottleWrite for custom read/write.

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

                            emailThrottleRead

                            callable

                            A callable that returns throttle data. If not specified, throttle data is read from emailThrottleFile.

                            ChangeLog:

                            • v2.1: introduced
                            emailThrottleWrite

                            callable

                            A callable that receives throttle data as a single param. If not specified, throttle data is written to emailThrottleFile.

                            ChangeLog:

                            • v2.1: introduced
                            emailTraceMask

                            E_ERROR | E_WARNING | E_USER_ERROR | E_USER_NOTICE

                            Specify which types of errors should include a backtrace

                            errorHandler options
                            • errorHandler options may be set via the Debug object 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).
                            • stopping error event's propagation will also prevent continuation to prev handler
                            errorReporting

                            E_ALL | E_STRICT

                            What errors the errorHandler should handle.

                            Bitmask of error types (or "system", which will use the currently configured php value)

                            If we're not handling error and continueToPrevHandler is true, the error will be passed to prev handler (if there was one).

                            onError

                            null

                            Set to something callable.

                            • Shortcut for subscribing to errorHandler.error event
                            • Will also get called on fatal errors.
                            • Callback will receive a single param: \bdk\ErrorHandler\Error $error

                            ChangeLog:

                            • v1.2: callable receives array of error info
                            • v2.0: callable receives a \bdk\PubSub\Event object
                            • v2.0.1: Replace previous onError value (2.0 added an additional subscriber)
                            • v3.0: callable receives a \bdk\ErrorHandler\Error object extends \bdk\PubSub\Event
                            onEUserError

                            log

                            • This library changes the default behavior of E_USER_ERROR and E_RECOVERABLE_ERROR from terminate to continue
                              Unless we're continuing to a previous error handler. In which case, this behavior will be dictated by prev handler.
                            • For default behavior, use the "normal" value
                            Using an error handler affects the behavior of E_USER_ERROR and E_RECOVERABLE_ERROR.
                            The More You Know
                            no custom error handler
                            treated as fatal / script terminates
                            custom error handler that returns false
                            treated as fatal / script terminates
                            custom error handler that does not return false
                            not treated fatal / script continues

                            This config option gives you control

                            If error is being passed to a previous error handler:
                            • We pass-the-buck & this option has no effect
                            • The behavior is controlled by the previous handler.

                            allowed values:

                            "continue"
                            • Script will continue
                            • Error will not be logged by PHP
                            "log"
                            (default)
                            • Script will continue
                            • Error will be logged if error event's propagation not stopped and if $error['continueToNormal'] == true
                            "normal"
                            Continue to "normal" error handler.
                            PHP will log error
                            Script will terminate.
                            null|false
                            Behavior based on the value of $error['continuetoNormal'].
                            See errorHandler.error event

                            ChangeLog:

                            • v2.1: introduced

                            Events

                            \bdk\Debug::EVENT_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.
                            \bdk\Debug::EVENT_CONFIG

                            published when config is updated

                            • Call $event->getSubject() to get the debug object
                            • $event->getValues() to get changed config values
                            Changelog:
                            • v3.0 - 'config' value removed in favor of $event->getValues()
                            • v2.1 - 'config' value added
                            • v2.0 - introduced
                            \bdk\Debug::EVENT_DUMP_CUSTOM

                            published when dumping an unknown "abstraction"`

                            Changelog:
                            • v3.0 - added
                            \bdk\Debug::EVENT_LOG

                            published when a debug method is called

                            • Only published when "collect" is true
                            • 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

                            Custom methods

                            Create custom methods by subscribing to this event.

                            For example you can call $debug->myMethod("arg1") (which isn't a core method). Rather than error out, this event will be published (just as it is for core methods).

                            $event['meta']['isCustomMethod'] will exist with a value of true

                            This event "bubbles" up its ancestor channels.
                            Calling stopPropagation() will prevent this
                            Changelog:
                            • v2.1 - publish when calling inaccessible method (custom methods)
                            • v2.0 - introduced
                            \bdk\Debug::EVENT_MIDDLEWARE

                            published before middleware writes to response

                            This event only applies if using PHPDebugConsole's middleware

                            • Call $event->getSubject() to get debug instance
                            • $event['request'] contains the ServerRequestInterface
                            • $event['response'] contains the ResponseInterface
                            Changelog:
                            • v3.0 - introduced
                            \bdk\Debug::EVENT_OBJ_ABSTRACT_END

                            published after object is inspected

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

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

                            Call $event->getSubject() to get the inspected object
                            This event "bubbles" up its ancestor channels.
                            Calling stopPropagation() will prevent this
                            \bdk\Debug::EVENT_OBJ_ABSTRACT_START

                            published before object is inspected

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

                            Subscribers to this event may:
                            • set `isExcluded`
                            • set `collectPropertyValues` (boolean)
                            • set `collectMethods` (boolean)
                            • set `propertyOverrideValues`
                            • set `stringified`
                              set this value in lieu of a __toString method..
                              example: DateTime objects don't have a __toString() method, so PHPDebugConsole uses its \bdk\Debug::EVENT_OBJ_ABSTRACT_START subscriber to set stringified to a human readable format
                            • set `traverseValues`
                            Call $event->getSubject() to get the object being inspected
                            This event "bubbles" up its ancestor channels.
                            Calling stopPropagation() will prevent this
                            Changelog:
                            • v2.3 - added `propertyOverrideValues`
                            output

                            published when it's time to output the log

                            Published on current and all descendant channels

                            subscriber with high priority can append log and modify the log before it's output

                            subscriber with low priority modify the generated $event['output']

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

                            outputLogEntry

                            for each enabled output plugin, published as each individual log entry is output

                            Use this event to customize how a particular method is displayed / or to handle custom methods (unhandled methods will be handled the same as a plain 'ol log() call).

                            • \bdk\Debug::EVENT_LOG is published when you call a debug method.
                            • \bdk\Debug::EVENT_OUTPUT_LOG_ENTRY is published when that log entry is output
                            • Call $event->getSubject() to get debug instance
                            • Call $event->stopPropagation() to prevent the default output
                            • $event['method'] contains the called debug method
                            • $event['args'] contains the arguments passed
                            • $event['meta'] contains meta information
                            • $event['return'] = null set to non-null to override
                            • $event['outputAs'] = output "plugin" instance (ie the OutputHtml object)
                            Changelog:
                            • v3.0 - getSubject() returns debug instance, previously returned output plugin
                              added $event['outputAs']
                            • v2.1.1 - add the return value
                            • v2.1 - introduced
                            \bdk\Debug::EVENT_PLUGIN_INIT

                            Published exclusively to the plugin being added

                            Use this event to do any initialization a plugin may require.

                            • Call $event->getSubject() to get debug instance
                            Changelog:
                            • v3.0 - added
                            \bdk\Debug::EVENT_PRETTIFY

                            Prettify php://input, Guzzle message bodies, and curl response body

                            We will prettify html, json, & xml. Use this event to customize, or to handle other content-types

                            • Call $event->stopPropagation() if handling
                            • $event['contentType'] contains the content/mime type
                            • $event['value'] contains the string to prettify
                            Changelog:
                            • v3.0 - added
                            \bdk\Debug::EVENT_STREAM_WRAP

                            Modify PHP code as it's loaded

                            If enableProfiling is enabled, \bdk\Debug::EVENT_STREAM_WRAP will be published when a file gets required/included.

                            Internally we use this event to inject declare(ticks=1); - necessary for our profile method.

                            • $event->getSubject() returns the php://memory resource that will contain the modified PHP code
                            • $event['content'] contains file contents
                            • $event['filepath'] contains the filepath being required
                            \bdk\ErrorHandler::EVENT_ERROR

                            published when a php error occurs

                            • Call $event->getValues() to get all error info
                            • Call $event->stopPropagation() to prevent continuation to previous error handler
                            \bdk\PubSub\Manager::EVENT_PHP_SHUTDOWN

                            Published when script execution finishes or exit() is called

                            Provided via our underlying event manager

                            This event is essentially a helper/wrapper for register_shutdown_function

                            Routes (output)

                            ChromeLogger

                            ChromeLogger outputs your log via http headers. The log is viewed in your browser's console via extension/addon

                            No PHP/server-side dependency required

                            Browser Support:

                            ChromeLogger website

                            AJAX Example

                            Non text/html example

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

                            See also:

                            ChromeLogger uses a single header which can get quite large.

                            If there's a proxy or load-balancer between you and the server being debugged, the large header is an issue.

                            Some shared hosting will 500 if a large header is attempted.

                            As a workaround you can set the headerMaxPer option to limit the output

                            Email

                            Email the log!

                            It may be useful to email the log if an error occured…

                            There are two ways to go about collecting and emailing log info

                            • See the emailLog configuration option
                              • This option does not require output to be true
                            • Set outputAs to "email" conditionally.. say for a specific user performing a specific action
                              • output must also be set to true
                            • Raw log data will be serialized & base64-encoded
                            • Unserialize with Debug::_getInstance()->routeEmail->unserializeLog() or \bdk\Debug\Route\Email::unserializeLog()
                            • Import the data with \bdk\Debug::setData($unserialized)
                            Remember:
                            collect must be set true for there to be any log entries to email!

                            Firephp

                            No PHP/server-side dependency required

                            Browser Support:

                            FirePHP website

                            AJAX Example

                            Non text/html example

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

                            See also:

                            Html

                            The default route

                            Script

                            Log is output as <script> tag with console.xxx calls

                            <script type="text/javascript">
                            console.log("hello world");
                            console.log("etc.");
                            </script>
                            Example Source
                            $debug = new \bdk\Debug(array(
                                'key' => 'example_password',
                                'route' => 'script',
                            ));
                            
                            $debug->alert('This is the script route example');
                            $debug->info('this is a script test');
                            $debug->table(array(
                                array('city' => 'Atlanta', 'state'=>'GA', 'population'=>472522,),
                                array('city' => 'Buffalo', 'state'=>'NY', 'population'=>256902,),
                                array('city' => 'Chicago', 'state'=>'IL', 'population'=>2704958,),
                                array('city' => 'Denver', 'state'=>'CO', 'population'=>693060,),
                                array('city' => 'Seattle', 'state'=>'WA', 'population'=>704352,),
                                array('city' => 'Tulsa', 'state'=>'OK', 'population'=>403090,),
                            ), 'Table');
                            
                            echo 'This example output can be found in your browser console!';
                            Example Output
                            This example output can be found in your browser console!

                            Stream

                            Stream to STDERR or file pointer

                            CLI scripts

                            This is the default route for command line scripts.

                            When used in command-line context:

                            • default stream: STDERR
                            • this route abides by the global output value (logs only pushed to stream when true).
                            • key config has no effect in console context
                            • pretty ANSI color output
                            // begin outputting log entries to specified filepath
                            // primary route is unaffected / this will supplement
                            $debug->setCfg('stream', '/some/filepath.txt');
                            
                            // only output log to filepath
                            // 'output' will need to be true or 'key' set & matching
                            $debug->setCfg(array(
                                'route' => 'stream',
                                'stream' => '/some/filepath.txt',
                            ));
                            

                            Text

                            Plain / boring text output

                            Example Source
                            $debug = new \bdk\Debug(array(
                                'collect' => true,
                                'output' => true,
                                'route' => 'script',
                            ));
                            
                            $debug->alert('this is an alert!');
                            $debug->info('you have 30 minutes to move your car');
                            $debug->warn('your car has been impounded');
                            $debug->error('your car has been crushed into a cube');
                            $debug->table(array(
                                array('city' => 'Denver', 'state'=>'CO', 'population'=>693060,),
                                array('city' => 'Seattle', 'state'=>'WA', 'population'=>704352,),
                                array('city' => 'Tulsa', 'state'=>'OK', 'population'=>403090,),
                            ), 'Table');
                            
                            Example Output
                            》[Alert ⦻ error] this is an alert!《
                            ℹ Built In 187.427 ms
                            ℹ Peak Memory Usage: 4 MB / redacted MB
                            ℹ you have 30 minutes to move your car
                            ⚠ your car has been impounded
                            ⦻ your car has been crushed into a cube
                            Table = array(
                                [0] => array(
                                    [city] => "Denver"
                                    [state] => "CO"
                                    [population] => 693060
                                )
                                [1] => array(
                                    [city] => "Seattle"
                                    [state] => "WA"
                                    [population] => 704352
                                )
                                [2] => array(
                                    [city] => "Tulsa"
                                    [state] => "OK"
                                    [population] => 403090
                                )
                            )
                            

                            Wamp check this out

                            Log entries are published immediately to a WAMP (Web Application Messaging Protocol) router

                            A "client" web-page listening to the WAMP router renders the log in "real-time"

                            Debug without adding any headers/text/markup to the output.

                            Great for debugging

                            • AJAX calls
                            • Command Line Applications
                            • API requests
                            • Any request returning something other than HTML (css, javascript, json, xml, binary, whatever)
                            • Plain 'ol html web pages

                            Requires:

                            How-To Guides & Integrations

                            Use PHPDebugConsole with the frameworks and tools you already use.

                            Frameworks

                            How-To Guides and plugins for common frameworks

                            CakePHP v4

                            CakePHP

                            Add debug configuration options to app.php or app_local.php

                            'PHPDebugConsole' => array(
                                'key' => 'dingus',
                            ),

                            Register plugin in Application::bootstrap()

                            $this->addPlugin(new \bdk\Debug\Framework\Cake4());

                            CodeIgniter (coming soon)

                            Laravel

                            Laravel

                            Setup & Configure

                            • Require bdk/debug via composer (how)
                            • Edit your laravel .env file and add PHPDEBUGCONSOLE_KEY = somePassword
                            • "publish" (ie copy) the config file and customize the config

                              run php artisan vendor:publish --tag=config

                              You should now have a config/phpDebugConsole.php config file

                              This file can be used to set all PHPDebugConsole config options including some Laravel-specific options

                              • laravel is a list of laravel-specific information that you would like to collect / output>
                              • options contains collector-specific options for the above

                            Using

                            Access your Laravel site with ?debug=somePassword (where "somePassword" is the password/key set in config/phpDebugConsole.php… likely the PHPDEBUGCONSOLE_KEY value)

                            Slim2 Framework

                            Slim Framework v2

                            Example Source
                            /*
                                create slim v2 app
                            */
                            $app = new \Slim\Slim(array(
                                'debug' => false,
                            ));
                            /*
                                Add logging via PHPDebugConsole
                            */
                            $app->hook('slim.before', function () use ($app) {
                                $app->log->setWriter(new \bdk\Debug\Framework\Slim2());
                            });
                            /*
                                Add Routes & Run
                            */
                            $app->get('/hello/:name', function ($name) {
                                echo 'Slim, '.$name.'<br />';
                            });
                            $app->run();

                            Symfony

                            Symfony

                            1. Add PhpDebugConole to your project via composer (how)
                            2. Update bundles.php / add this line
                              bdk\Debug\Framework\Symfony\DebugBundle\BdkDebugBundle::class => ['all' => true],
                            3. Add config/packages/dev/bdk_debug.yaml
                              bdk_debug:
                                collect: true
                                output: true

                            Yii 1.1

                            Yii 1.1 framework

                            Our Yii 1.1 component will

                            • Add a Yii log route
                            • decorate Yii::app()->db with \bdk\Debug\Collector\Pdo (log PDO queries)
                            • pass errors through our ErrorHandler
                            • Add Yii::app()->debug

                            Require bdk/debug via composer (how)

                            Edit your Yii config

                            array(
                              // add to components
                              'components' => array (
                                'phpDebugConsole' => array (
                                  'class' => '\\bdk\\Debug\\Framework\\Yii1_1\\Component',
                                  // debug config values
                                  // best to replace 'collect' & 'output' with 'key'
                                  'collect' => true,
                                  'output' => true,
                                  // optional yii specific options
                                  'yii' => array(
                                    'ignoredErrors' => true, // yii 1.1 framework throws a lot of deprecation and notices
                                                          // we "ignore" these errors
                                                          // this setting will show a summary of these ignored errors
                                    'log' => true, // whether to set up a yii log route and capture Yii log messsaegs
                                    'pdo' => true, // capture database queries
                                    'session' => true, // log session info / data
                                    'user' => true, // log current user info
                                  )
                                ),
                              ),
                              // add to preload
                              'preload' => array('phpDebugConsole'),
                              // may need to add an alias
                              'aliases' => array(
                                'bdk.Debug.Framework' => 'path/to/Debug/Framework/Yii1_1',
                              ),
                            );

                            You may also want to define YII_DEBUG when bootstraping your app

                            define('YII_DEBUG', true);
                            

                            Yii 2.x

                            Yii 2.0

                            Require bdk/debug via composer (how)

                            Edit your Yii config

                            
                            /*
                                Add to bootstrao and modules arrays
                                Make sure that 'phpDebugConsole' comes first in the boostrap array
                                  to ensure we intercept the instantiation of the database connection
                            */
                            $config['bootstrap'][] = 'phpDebugConsole';
                            $config['modules']['phpDebugConsole'] = [
                                'class' => 'bdk\Debug\Framework\Yii2\Module',
                                // debug config values
                                // best to replace 'collect' & 'output' with 'key'
                                'collect' => true,
                                'output' => true,
                                // optional yii specific options
                                'yii' => [
                                    'events' => true, // summary of all dispatched events
                                    'log' => true, // whether to set up a yii log target and capture Yii log messsaegs
                                    'pdo' => true, // capture database queries
                                    'session' => true, // log session info / data
                                    'user' => true, // log current user info
                                ],
                            ];
                            

                            Decorators

                            PHPDebugConsole includes Adaptors / Decorators / Helpers / Proxies / Wrappers for common "components"

                            Doctrine DB Abstraction Layer

                            Doctrine Database Abstraction Layer
                            Example Source
                            /*
                                Get the Doctrine connection obj
                            */
                            $conn = \Doctrine\DBAL\DriverManager::getConnection(array(
                                'url' => 'mysql://user:secret@localhost/mydb',
                            ));
                            
                            /*
                                Instantiate PHPDebugConsole's Doctrine Logger and set Doctrine's logger
                            */
                            $logger = new \bdk\Debug\Collector\DoctrineLogger($conn);
                            $conn->getConfiguration()->setSQLLogger($logger);
                            
                            $statement = $conn->prepare('SELECT *
                                FROM `users`
                                WHERE `username` = :username');
                            $username = 'james.bond';
                            $statement->bindParam(':username', $username, PDO::PARAM_STR);
                            $statement->execute();
                            Example Output
                                • Built In 187.427 ms
                                • Peak Memory Usage ?⃝: 4 MB / redacted MB
                                • Doctrine: sqlite:///:memory:
                                  • logged operations: 1
                                  • total time: 73.9098 μs
                                  • max memory usage = 0 B
                                  • connection info = array(
                                    • url=>sqlite:///:memory:
                                    • driver=>pdo_sqlite
                                    • host=>localhost
                                    • memory=>true
                                    )
                                • SELECT * FROM `users`…
                                  • SELECT * FROM `users` WHERE `username` = :username
                                  • parameters
                                     valuetype
                                    :usernamejames.bondPDO::PARAM_STR
                                  • duration: 73.9098 μs
                                  • memory usage = 0 B
                                  • Use SELECT * only if you need all columns from table

                                        Guzzle

                                        Guzzle
                                        Initiate a guzzle client with PHPDebugConsole middleware
                                        $stack = \GuzzleHttp\HandlerStack::create();
                                        $stack->push(
                                            new \bdk\Debug\Collector\GuzzleMiddleware(array(
                                                'inclRequestBody' => true,  // default is false
                                                'inclResponseBody' => true, // default is false
                                            ))
                                        );
                                        
                                        $client = new \GuzzleHttp\Client(array(
                                            'cookies' => true,
                                            'handler' => $stack,
                                        ));
                                        
                                        $response = $client->request('GET', 'http://example.com/');
                                        Example Output
                                        • Built In 187.427 ms
                                        • Peak Memory Usage ?⃝: 4 MB / redacted MB
                                        • Guzzle(GET, http://example.com/)
                                          • request headers = GET / HTTP/1.1 User-Agent: GuzzleHttp/6.5.5 curl/7.73.0 PHP/7.4.13 Host: example.com
                                          • request body = null
                                          • response headers = HTTP/ 1.1 200 OK Accept-Ranges: bytes Age: 293825 Cache-Control: max-age=604800 Content-Type: text/html; charset=UTF-8 Date: Fri, 05 Mar 2021 20:31:36 GMT Etag: "3147526947" Expires: Fri, 12 Mar 2021 20:31:36 GMT Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT Server: ECS (dab/4BF0) Vary: Accept-Encoding X-Cache: HIT Content-Length: 1256
                                          • response body = <!doctype html> <html> <head> <title>Example Domain</title> <meta charset="utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style type="text/css"> body { background-color: #f0f0f2; margin: 0; padding: 0; font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } div { width: 600px; margin: 5em auto; padding: 2em; background-color: #fdfdff; border-radius: 0.5em; box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02); } a:link, a:visited { color: #38488f; text-decoration: none; } @media (max-width: 700px) { div { margin: 0 auto; width: auto; } } </style> </head> <body> <div> <h1>Example Domain</h1> <p>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</p> <p><a href="https://www.iana.org/domains/example">More information...</a></p> </div> </body> </html>
                                        Add PHPDebugConsole middleware to existing Guzzle client
                                        $guzzleClient->getConfig('handler')->push(
                                            new \bdk\Debug\Collector\GuzzleMiddleware(array(
                                                'inclRequestBody' => true,  // default is false
                                                'inclResponseBody' => true, // default is false
                                            ))
                                        );
                                        
                                        $response = $guzzleClient->request('GET', 'http://example.com/');
                                        Example Output
                                        • Built In 187.427 ms
                                        • Peak Memory Usage ?⃝: 4 MB / redacted MB
                                        • Guzzle(GET, http://example.com/)
                                          • request headers = GET / HTTP/1.1 User-Agent: GuzzleHttp/6.5.5 curl/7.73.0 PHP/7.4.13 Host: example.com
                                          • request body = null
                                          • response headers = HTTP/ 1.1 200 OK Age: 270774 Cache-Control: max-age=604800 Content-Type: text/html; charset=UTF-8 Date: Fri, 05 Mar 2021 20:31:36 GMT Etag: "3147526947+ident" Expires: Fri, 12 Mar 2021 20:31:36 GMT Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT Server: ECS (dab/4BF2) Vary: Accept-Encoding X-Cache: HIT Content-Length: 1256
                                          • response body = <!doctype html> <html> <head> <title>Example Domain</title> <meta charset="utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style type="text/css"> body { background-color: #f0f0f2; margin: 0; padding: 0; font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } div { width: 600px; margin: 5em auto; padding: 2em; background-color: #fdfdff; border-radius: 0.5em; box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02); } a:link, a:visited { color: #38488f; text-decoration: none; } @media (max-width: 700px) { div { margin: 0 auto; width: auto; } } </style> </head> <body> <div> <h1>Example Domain</h1> <p>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</p> <p><a href="https://www.iana.org/domains/example">More information...</a></p> </div> </body> </html>

                                        Monolog

                                        There are two ways to use PHPDebugConsole as a monolog "handler"

                                        1. MonologHandler

                                          PHPDebugConsole provides a monolog handler.

                                          This handler will pass along the monolog channel.

                                          Example Source
                                          $monolog = new \Monolog\Logger('PHPDebugConsole');
                                          $monolog->pushHandler(new \bdk\Debug\Collector\MonologHandler());
                                          $monolog->info('yup, it works');
                                          Example Output
                                          • Built In 187.427 ms
                                          • Peak Memory Usage ?⃝: 4 MB / redacted MB
                                          • yup, it works
                                        2. Psr-3 Logger

                                          Use Monolog's PSR-3 handler with PHPDebugConsole's PSR-3 logger

                                          Example Source
                                          $monolog = new \Monolog\Logger('PHPDebugConsole');
                                          $monolog->pushHandler(new \Monolog\Handler\PsrHandler($debug->logger));
                                          $monolog->info('yup, it works');
                                          Example Output
                                          • Built In 187.427 ms
                                          • Peak Memory Usage ?⃝: 4 MB / redacted MB
                                          • yup, it works
                                        PHPDebugLogger doesn't include monolog. Install separately if needed.
                                        Changelog:
                                        • v3.0: MonologHandler
                                        • v2.3: Psr-3 Logger

                                        MySqli

                                        Php's mysqli extension
                                        Example Source
                                        /*
                                            Instantiate and use PHPDebugConsole's MySqli client (in lieu of PHP's mysqli client)
                                        */
                                        $mysqli = new \bdk\Debug\Collector\MySqli('localhost', 'my_user', 'my_pass', 'my_db');
                                        
                                        $stmt = $mysqli->prepare("INSERT INTO `some_table` (`int`, `float`, `text`) VALUES (?, ?, ?)");
                                        $stmt->bind_param('idds', $int, $decimal, $float, $text);
                                        
                                        $int = 42;
                                        $float = 3.14;
                                        $text = 'sweet';
                                        
                                        // execute prepared statement
                                        $stmt->execute();

                                        PDO

                                        Php's PDO extension
                                        Example Source
                                        $pdo = new \PDO('sqlite::memory:');
                                        $pdoDebug = new \bdk\Debug\Collector\Pdo($pdo);
                                        
                                        // use $pdoDebug just as you would
                                        $stmt = $pdoDebug->prepare('SELECT *
                                            FROM `bob`
                                            WHERE e < :datetime');
                                        $datetime = date('Y-m-d H:i:s');
                                        $stmt->bindParam(':datetime', $datetime, PDO::PARAM_STR);
                                        $stmt->execute();

                                        PhpCurlClass

                                        PHP Curl Class
                                        Example Source
                                        $curl = new \bdk\Debug\Collector\PhpCurlClass(array(
                                            'inclResponseBody' => true,
                                        ));
                                        $curl->get('https://www.example.com/');

                                        PSR-3 (Logger)

                                        If you're using a library that uses psr/log getting up and runniing with PHPDebugConsole couldn't be easier.

                                        logger method maps to
                                        $logger->emergency() $debug->error()
                                        $logger->alert() $debug->alert()
                                        $logger->critical() $debug->error()
                                        $logger->error() $debug->error()
                                        $logger->warning() $debug->warn()
                                        $logger->notice() $debug->warn()
                                        $logger->info() $debug->info()
                                        $logger->debug() $debug->log()
                                        psr/log (PSR-3) example
                                        $debug = new \bdk\Debug(array(
                                            'collect' => true,
                                            'output' => true,
                                        ));
                                        
                                        $logger = $debug->logger;   // implements Psr\Log\LoggerInterface
                                        
                                        $logger->debug('This thing does {what}', array('what'=>'it all'));
                                        $logger->critical('I literally can\'t even');
                                        psr/log example output
                                        • Built In 187.427 ms
                                        • Peak Memory Usage ?⃝: 4 MB / redacted MB
                                        • This thing does it all
                                        • I literally can't even
                                        PHPDebugLogger doesn't include psr/log. Install separately if needed.
                                        Changelog:
                                        • v2.3

                                        PSR-16 (SimpleCache)

                                        psr/simple-cache
                                        Example Source
                                        $cache = new \bdk\Debug\Collector\SimpleCache($someSimpleCacheImplementation);
                                        $cache->get('twitterFeed');

                                        SoapClient

                                        Php's SoapClient class
                                        Example Source
                                        /*
                                            Use the PHPDebugConsole SoapClient (extends SoapClient)
                                        */
                                        $wsdl = 'http://www.SoapClient.com/xml/SQLDataSoap.wsdl';
                                        $soapClient = new \bdk\Debug\Collector\SoapClient($wsdl);

                                        SwiftMailer

                                        Swift Mailer
                                        Example Source
                                        /*
                                            Initialize Swift Mailer
                                        */
                                        $transport = new Swift_SendmailTransport('/usr/sbin/sendmail -bs');
                                        $mailer = new Swift_Mailer($transport);
                                        /*
                                            After initializing Swift Mailer, add Logger Plugin
                                        */
                                        $logger = new \bdk\Debug\Collector\SwiftMailerLogger();
                                        $mailer->registerPlugin($logger);
                                        /*
                                            Send a message
                                        */
                                        $message = (new Swift_Message('Definitely Not Spam'))
                                            ->setFrom(['bkfake-github@ryahoo.com' => 'Brad Kent'])
                                            ->setTo(['randyr@domain.org' => 'Randy Recipient'])
                                            ->setBody('Here is the message itself');
                                        $result = $mailer->send($message);

                                        Twig Templates

                                        Twig
                                        Example Source
                                        /*
                                            Instantiate Twig
                                        */
                                        $loader = new Twig_Loader_Filesystem(__DIR__);
                                        $twig = new Twig_Environment($loader);
                                        
                                        /*
                                            Add PHPDebugConsole's TwigExtension
                                        */
                                        $twig->addExtension(new \bdk\Debug\Collector\TwigExtension());
                                        
                                        echo $twig->render('test.twig', array(
                                            'name' => 'Test',
                                        ));

                                        PSR-7 & PSR-15

                                        Response (PSR-7)

                                        Debug object provides a writeToResponse method for outputting debug to PSR-7 response or HttpFoundation response object.

                                        See writeToResponse for more info.

                                        Middleware (PSR-15)

                                        PHPDebugConsole provides a PSR-15 Middleware you may use in your projects.

                                        Example Source
                                        /** @var Psr\Http\Server\MiddlewareInterface;*/
                                        $middlware = $debug->middleware;

                                        Changelog

                                        v3.0 – in development

                                        • Much improved HTML UI/UX
                                          • new drawer + filter sidebar
                                          • syntax highlighted json, xml, sql, php
                                          • first argument now sanitized (htmlspecialchars) by default
                                          • editor links (click on error to open relevant file/line in your editor/IDE)
                                          • objects - ability to toggle inherited methods
                                          • fatal error backtraces get context (file-snippets)
                                          • output log-entry divs replaced with more semantic ul/li
                                          • included files output as file tree
                                        • PHP 8.0 : Attributes logged
                                        • Included decorators/helpers for logging PDO, mysqli, Doctrine, Guzzle, Curl, SimpleCache, Soap, Twig, SwiftMailer
                                        • MiddlewareInterface (PSR-15), & new writeToResponse() method (PSR-7)
                                        • ErrorHandler v3 / new Error class (extends generic Event) replaces array
                                        • New AssetProviderInterface / addPLugin / removePlugin methods
                                        • New LogEntry object replaces array
                                        • New Abstraction object replaces array
                                        • rewritten javascript / css built from SCSS
                                        • Tons of small enhancements

                                        v2.3 – 2020-01-03

                                        • PSR-3 implementation
                                        • "Channels" (akin to monolog's channels) - see getChannel()
                                        • New methods:
                                        • New config options
                                          • outputHeaders (default true) Whether headers should be output (ie with chromeLogger and firePHP) this provides flexibility with frameworks, PSR7 responseInterface, etc
                                          • enableProfiling set to true if you will be using profile and profileEnd methods
                                        • value not shown for protected/private property that also has magic phpDoc annotation
                                        • ErrorHandler\ErrorEmailer throttle file not being created if doesn't exist
                                        • undefined variable throttleData in ErrorEmailer.php
                                        • Objects
                                          • Properties not returned by __debugInfo are now output with ability to show/hide (like private/protected)
                                          • debug.objAbstractStart : new event value : propertyOverrideValues. Similar to having a __debugInfo() method
                                          • debug.objAbstractEnd : properties have a new flag - forceShow: initially show the property/value (even if protected or private)
                                          • __debugInfo() is no longer called if collectPropertyValues is false
                                          • objects now check if a instanceof objects listed in objectExclude rather than exact class match
                                        • Request headers now logged by default (see config logEnvInfo)
                                        • HTML output :
                                          • clicking on strings/floats/ints will copy their values to the clipboard
                                          • Long strings are now initially collapsed / given "view-all" toggle
                                        • assert() - support for styling/substitutions
                                        • groupEnd() now accepts a single value. This value represents the group's return value and will be displayed when the group is both expanded and collapsed.
                                        • output() now accepts a config array.
                                        • Handle html_errors and docref_root php settings. Don't double htmlspecialchars() error message
                                        • Internal
                                          • OutputInterface : $path parameter removed from dump() method
                                          • tests for ErrorHandler & PubSub moved to their own repos
                                          • Wamp plugin now only base64-encodes strings that are not UTF-8

                                        v2.2 – 2018-06-18

                                        • Added clear() method
                                        • Custom methods can now be called statically
                                        • Issues when leaving summary groups open and outputting as HTML
                                        • Internal autoloader only registered if necessary
                                        • some \bdk\Debug\Utilities methods beefed up & now more useful outside debugger: arrayPathGet, arrayMergeDeep, & getCallerInfo

                                        v2.1.1 – 2018-05-21

                                        • setCfg('string', newValue) not properly returning previous value -> collect is always on. Bug introduced in v2.1. Unit-test added.
                                        • Chromelogger - invalid javascript console methods need to be mapped to log()
                                        • Script - invalid javascript console methods need to be be mapped to log()
                                        • return value added to debug.outputLogEntry event. Event is no longer worthless
                                        • alert() now publishes debug.outputLogEntry when being output
                                        • \bdk\Debug\Utilities::buildAttribString() - now with more utility
                                        • Can now instantiate via static method call, ie \bdk\Debug::_setConfig(), \bdk\Debug::_log('collect is false, so this is pointless'), etc. Because why not

                                        v2.1.0 – 2018-05-04

                                        • Custom methods: add your own custom methods by subscribing to the debug.log and/or debug.outputLogEntry events
                                        • Remove internal frames from fatal error trace (2.0.2 Regression)
                                        • Notice thrown when handling a fatal error with xdebug enabled & no backtrace frames
                                        • count()
                                          • optional 2nd param : Disable increment and/or output
                                          • when not using a label, file & line logged as meta data - output as title attribute for html
                                        • groupSummary() calls can now be nested & other groupSummary improvements
                                        • table()
                                          • Now accepts a Traversable object as param. Array-o-traversable was already a thing, but top-level Traversable had been overlooked
                                          • Just display stringified or __toString value if applicable
                                        • setting outputAs now clears previous value (unsubscribes events)
                                          (to use multiple output plugins/routes, use $debug->addPlugin())
                                        • POST requests : display php://input and content-type if $_POST is empty
                                        • debug.objAbstractStart event : reflector, hist, & debugMethod values now avail to subscribers
                                        • ChromeLogger & Script output now get stylish alerts
                                        • New config option: onEUserError gives control of E_USER_ERROR behavior
                                        • Internal
                                          • ErrorHandler and ErrorEmailer moved outside of bdk\Debug namespace / have no dependencies
                                          • Output classes now in Output namespace & implement OutputInterface
                                          • separate method & args in data.log
                                          • store some args as meta for alert(), table(), & groupSummary()
                                          • debug.output event now only published if cfg.output == true
                                          • moderate performance gains by using absolute function references (ie \func_get_args())
                                          • more unit tests

                                        v2.0.2 – Oops – 2018-02-02

                                        • Regression: 2.0.1 didn't output fatal errors as HTML
                                          (error captured after output took place)
                                        • static methods can now be called before instance created
                                          ie \bdk\Debug::_setCfg(array('collect'=>true, 'output'=>true));
                                        • Unit tests for fatal errors! (It's magic)

                                        v2.0.1 – 2018-01-22

                                        • emailLog feature broken. Fix and make better than new
                                        • Abstracter: initializing with a `objectsExclude` value, not adding default "\bdk\Debug" exclusion
                                        • Utilities::arrayMergeDeep: add condition for array(object, 'string') (callable)
                                          "edge case" where updating cfg callable twice munges the stored callable
                                        • onLog, onError, & onOutput config values : now replace existing subscriber set via setCfg, rather than add new subscriber (doesn't not affect adding subscribers via eventManager)
                                        • PubSub\Manager now publishes a "php.shutdown" convenience event - subscribe and unsubscribe to shutdown!
                                        • Some internal tweaks and variable name changes
                                        • Unit-tests for emailing log & errors
                                        • HHVM Travis build now works!

                                        v2.0 – The Refactoring – 2017-12-26

                                        • 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
                                          • more docBlock parsing.
                                            • Support for {@inheritdoc}
                                            • properties and methods defined via @method & @property tags incoporated into object's property & method list
                                            • links created for @link & @see (when url)
                                          • 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
                                          • if a method param's default-value is a constant, the constant's name, rather than value is displayed (php >= 5.4.6)
                                        • 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
                                        • New output options:
                                          chromeLogger
                                          ajax and non-html output now defaults to ChromeLogger (was FirePHP)
                                          Firefox has built-in support, Chrome has an extension
                                          wamp
                                          sends log to wamp router in realtime for true console-like logging
                                        • 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, error, info, & warn 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
                                        • group() and groupCollapsed()
                                          • default label is now current function's name (or "group" if outside of a function)
                                          • can now pass "hideIfEmpty" "option"
                                        • Arrays matching array(Object, 'string') now interpreted & displayed as a callable
                                        • Better handling of single param passed to log, error, info, & warn (whether htmlspecialchars & visual whitespace applied)
                                        • 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
                                        PHPDebugConsole
                                          • request headers
                                             value
                                            Accepttext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
                                            Accept-Encodingbr,gzip
                                            Accept-Languageen-US,en;q=0.5
                                            Connectionclose
                                            Content-Length35
                                            Content-Typeapplication/x-www-form-urlencoded
                                            CookieSESSIONID=5umr2d3e392f6idhvpadiqs7r0; =
                                            Hostwww.bradkent.com
                                            If-Modified-SinceFri, 22 Jan 2021 02:35:04 GMT
                                            User-AgentCCBot/2.0 (https://commoncrawl.org/faq/)
                                          • $_COOKIE
                                             value
                                            SESSIONID5umr2d3e392f6idhvpadiqs7r0
                                          • $_POST = array(
                                            • username=>superman
                                            • password=>█████████
                                            )
                                          • response headers
                                             value
                                            Content-Typetext/html
                                            CookieSESSIONID=5umr2d3e392f6idhvpadiqs7r0
                                          • Not logging response body for Content-Type "text/html"
                                            • 17 files required
                                            • 12 files logged
                                            • array(
                                              • /var/www=>array(
                                                • 0=>controllers/php/Debug.php
                                                • vendor=>array(
                                                  • 0=>5 omitted
                                                  )
                                                • views/php/debug=>array(
                                                  • 0=>index.php
                                                  • 1=>changelog.php
                                                  • 2=>config.php
                                                  • 3=>events.php
                                                  • 4=>framework.php
                                                  • 5=>index.php
                                                  • 6=>methods.php
                                                  • 7=>overview.php
                                                  • 8=>route.php
                                                  )
                                                • 1=>bootstrap.php
                                                • 2=>index.php
                                                )
                                              )
                                            • git branch: master
                                            • Built In 187.427 ms
                                            • Peak Memory Usage ?⃝: 2 MB / redacted MB
                                            • PDO info: mysql, Localhost via UNIX socket
                                              • logged operations: 1
                                              • total time: 0.05432
                                              • max memory usage = 28.12 kB
                                              • server info = array(
                                                • Flush tables=>1
                                                • Open tables=>1224
                                                • Opens=>5657
                                                • Queries per second avg=>0.382
                                                • Questions=>254442
                                                • Slow queries=>0
                                                • Threads=>3
                                                • Uptime=>665846
                                                • Version=>5.7.19
                                                )
                                            • SELECT * FROM `user`…
                                              • SELECT * FROM `user` WHERE `id` = '1' LIMIT 1
                                              • duration: 600 μs
                                              • memory usage = 21.21 kB
                                              • rowCount = 1
                                            • get("exampleDebugOutput") took 0.00070sec
                                            • Notice: Undefined variable: foo, /path/to/myController.php (line 34)
                                              • PHP Version = 7.4.13
                                              • ini files = array(
                                                • /path/to/php.ini
                                                • /usr/local/etc/php/7.4/conf.d/ext-opcache.ini
                                                )
                                              • date.timezone = America/Chicago
                                              • memory_limit = redacted MB
                                              • Xdebug is not installed
                                              • $_SERVER = array(
                                                • CONTENT_LENGTH=>35
                                                • CONTENT_TYPE=>application/x-www-form-urlencoded
                                                • REMOTE_ADDR=>
                                                • REQUEST_METHOD=>POST
                                                • REQUEST_TIME=>
                                                • REQUEST_URI=>/myForm
                                                • SERVER_ADDR=>
                                                • SERVER_NAME=>
                                                )
                                                • session.cookie_httponly should be enabled
                                                • session.cache_limiter = nocache
                                                • session save_path = /var/tmp/
                                                • session name = SESSIONID
                                                • session id = e8ur1fvnbp26fj4ganpadbf3dd
                                                • $_SESSION = array()
                                                Fork me on GitHub