Loading…

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

Overview & Usage

PHPDebugConsole is a browser/javascript like console class for PHP (logging, debugging, value inspecting, etc).


    • 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 / stream
        • 4=>ServerLog
        • 5=><script>
        • 6=>"plugin" (send log realtime via websockets, etc)
        )
      • 1=>password protected
      • 2=>errors (even fatal) are captured / logged / displayed
      • 3=>send error notices via email, Discord, Slack, or Teams (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
      implements
      • Stringable
      properties
      private offLimits = I'm a private property
      methods
      public __toString(): string

      return value

      • It's Magic
      private foo(string $bar): string
    • 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)=>1703048757
        • 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

    Add to composer.json

    {
        "require": {
            "bdk/debug": "^2.3"
        }
    }

    or

    composer require bdk/debug:^2.3 --update-no-dev

    Installation Option B:

    Download and extract PHPDebugConsole to your webserver

    You will need to include and register our autoloader

    require 'path-to/src/Debug/Autoloader.php';
    $autoloader = new \bdk\Debug\Autoloader();
    $autoloader->register();
    // you can now instantiate Debug
    $debug = new \bdk\Debug();
    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
    • Github Build Status
    • Codacy Score
    • Code Climate - Maintainability
    • Code Climate - Coverage

    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
    message to be displayed
    $level
    danger, info, success, or warning
    $dismissible
    (false) Whether to display a close icon/button

    Return Value

    $this

    Can use styling & substitutions.
    If using substitutions, 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

      • pretending to attempt database connection
      Changelog:
      • v2.0 - introduced
      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

      Return Value

      $this
      Example Source
      $debug->assert(1 + 1 === 2, 'basic addition');
      $debug->assert(1 * 1 === 2, 'basic multiplication');
      $debug->assert(false);  // no message parameter
      Example Output

        • 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 $bitmask = bdk\Debug::CLEAR_LOG)

        Clear the log

        Parameters

        $bitmask
        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 warn & error
        self::CLEAR_SUMMARY : Clear summary entries (excluding warn & error)
        self::CLEAR_SUMMARY_ERRORS : Clear warn & error within summary groups
        self::CLEAR_ALL : Clear all log entries
        self::CLEAR_SILENT : Don't add log entry

        Return Value

        $this
        This method executes even if collect is false
        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

          • 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.

          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
          (ie, just get the current count)
          \bdk\Debug::COUNT_NO_OUT : don't output/log

          Return Value

          int
          The new count (or current count when using COUNT_NO_INC)
          Count is maintained even when collect is false
          If collect = false, count() will be performed "silently"
          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

            • count = 1
            • myCounter = 1
            • count = 2
            • count = 3
            • after loop
            • count = 4
            • myCounter = 4
            Changelog:
            • v2.1: $flags argument added
            countReset(mixed $label = null[, int $flags = null])
            countReset(int $flags)

            Resets the counter

            Parameters

            $label
            (optional) specify the counter to reset
            $flags
            (optional) currently only one option :
            \bdk\Debug::COUNT_NO_OUT` : don't output/log

            Return Value

            $this
            Counter is reset even when debugging is disabled (ie collect is false).
            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

              • myCounter = 5
              • after loop
              • myCounter = 8
              • 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

              Return Value

              $this
              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

                • the four basic methods, log, info, warn, error
                • User logged in = false
                • DROP TABLE = Students
                • No Such Table = Students
                Supports substitution & formatting, see log() for examples
                Heads Up: htmlspecialchars() is not applied to first argument
                Good
                $debug->error('unsanitized user input', $_GET['whatever']);
                Bad
                $debug->error($_GET['whatever']);

                This behavior will not exist in v3.0

                group(mixed ...$arg)

                Create a new inline group

                Parameters

                ...$arg
                label / values

                Return Value

                $this
                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

                  • This is the outer level
                  • doStuff
                    • Level 2
                    • group(a, true, null)
                      • Level 3
                      • Level 3 warning
                    • isPlaneHere(6.7, 105.62)
                      • Analyizing the data...
                      • return = false
                    • found = false
                    • Back to level 2
                  • Back to the outer level
                  groupCollapsed(mixed ...$arg)

                  Create a new inline group

                  Parameters

                  ...$arg
                  label / values

                  Return Value

                  $this

                  Unline group(), groupCollapsed(), will initially be collapsed

                  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

                    • This is the outer level
                    • doStuff
                      • Level 2
                      • group(a, true, null)
                        • Level 3
                        • Level 3 warning
                      • isPlaneHere(6.7, 105.62)
                        • Analyizing the data...
                        • return = false
                      • found = false
                      • Back to level 2
                    • Back to the outer level
                    groupEnd(mixed $value = bdk\Debug\Abstracter::UNDEFINED)

                    Close current group

                    Parameters

                    $value
                    (optional) "return" value

                    Return Value

                    $this

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

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

                    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

                      • This is the outer level
                      • doStuff
                        • Level 2
                        • group(a, true, null)
                          • Level 3
                          • Level 3 warning
                        • isPlaneHere(6.7, 105.62)
                          • Analyizing the data...
                          • return = false
                        • 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 at the top of the output

                      Parameters

                      $priority
                      (0) The higher the priority, the earlier the group will appear in output

                      Return Value

                      $this
                      This method does not have a web console API equivalent.
                      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
                      • I'm at the top of the log

                      • foo
                      "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.

                      Return Value

                      $this
                      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

                        • 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

                        Return Value

                        $this
                        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

                          • the four basic methods, log, info, warn, error
                          • User logged in = false
                          • DROP TABLE = Students
                          • No Such Table = Students
                          Supports substitution & formatting, see log() for examples
                          Heads Up: htmlspecialchars() is not applied to first argument
                          Good
                          $debug->info('unsanitized user input', $_GET['whatever']);
                          Bad
                          $debug->info($_GET['whatever']);

                          This behavior will not exist in v3.0

                          log(mixed ...$arg)

                          Log general information

                          Parameters

                          ...$arg
                          message / values

                          Return Value

                          $this
                          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('%cStyling:%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,
                              'infinity' => INF,
                              'notANumber' => NAN,
                              '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

                            • param1
                            • param1 = param2
                            • param1, param2, param3
                            • string, 123, 123.4, 123.4, array(
                              • foo=>bar
                              )
                              , true, null
                            • Styling: as of v2.0: supports styling and substitution
                            • array = array(
                              • string=>foobar
                              • string_html=><span class="test"> htmlspecialchar'd &amp; whitespace shown</span>
                              • boolTrue=>true
                              • boolFalse=>false
                              • null=>null
                              • int=>123
                              • now=>1703048757
                              • float=>3.14159265
                              • infinity=>INF
                              • notANumber=>NaN
                              • 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)
                            Heads Up: htmlspecialchars() is not applied to first argument
                            Good
                            $debug->log('unsanitized user input', $_GET['whatever']);
                            Bad
                            $debug->log($_GET['whatever']);

                            This behavior will not exist in v3.0

                            profile(string $name = null)

                            Starts recording a performance profile

                            Parameters

                            $name
                            Optional profile name

                            Return Value

                            Debug
                            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

                              • 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

                              Return Value

                              $this
                              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

                                • 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 an 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

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

                                  Start a timer identified by label

                                  Parameters

                                  $label
                                  (optional) unique label

                                  Return Value

                                  $this

                                  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

                                  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

                                    • time: 290.8707 μs
                                    • timer a: 1.4009 ms
                                    • time: 1.57 ms
                                    • timer a: 1.4009 ms
                                    timeEnd(string $label = null[, bool|string $returnOrTemplate = %label: %time sec[, int $precision = 4]])

                                    Behaves like a stopwatch.. logs and (optionaly) returns running time

                                    Parameters

                                    $label
                                    (optional) unique label
                                    $returnOrTemplate
                                    string: "%label: %time
                                    boolean: If true, only return time, rather than log it
                                    $precision
                                    rounding precision (pass null for no rounding)

                                    Return Value

                                    $this|float|false
                                    The duration (in sec).
                                    • If label is passed, the timer is paused. Additional calls to timeEnd('label') will return the same value until unpaused with time('label')
                                    • If no label is passed, timer is removed from a timer stack and logged
                                    • $returnOrTemplate: if true, the time will be returned as a float (in seconds) and will not be logged.
                                      If string, will be used as the template for the output. Default: "%label: %time sec" (as of v1.3.2)
                                    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

                                      • time: 290.8707 μs
                                      • timer a: 1.4009 ms
                                      • time: 1.57 ms
                                      • timer a: 1.4009 ms
                                      timeGet(string $label = null[, bool|string $returnOrTemplate = %label: %time sec[, int $precision = 4]])

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

                                      Parameters

                                      $label
                                      (optional) unique label
                                      $returnOrTemplate
                                      string: "%label: %time
                                      boolean: If true, only return time, rather than log it
                                      $precision
                                      rounding precision (pass null for no rounding)

                                      Return Value

                                      $this|float|false
                                      The duration (in sec). false if specified label does not exist
                                      This method does not have a web console API equivalent.
                                      Example: 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

                                        • queryDb(INSERT INTO student (id, name, age) VALUES ("1", "alan", 28))
                                          • queryDb(SELECT * FROM student ORDER BY age)
                                            • query db: 891.9239 μs
                                            timeLog(string $label = null[, mixed ...$args = null])

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

                                            Parameters

                                            $label
                                            (optional) unique label
                                            ...$args
                                            (optional) additional values to be logged with time

                                            Return Value

                                            $this

                                            also logs additional arguments

                                            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

                                              • timer a: 1.7359 ms, foo, array(
                                                • foo=>bar
                                                )
                                              • other things happen
                                              • timer a: 2.5342 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

                                              Return Value

                                              $this
                                              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

                                                • trace
                                                   filelinefunction
                                                  0/path/to/mypage.inc.php7
                                                  1/path/to/mypage.inc.php9{closure}
                                                  2/path/to/mypage.inc.php2func2
                                                  3/path/to/mypage.inc.php13func1
                                                • sorting is disabled for trace tables
                                                warn(mixed ...$arg)

                                                Log a warning

                                                Parameters

                                                ...$arg
                                                message / values

                                                Return Value

                                                $this
                                                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

                                                  • 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

                                                  Config & Utility methods

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

                                                  Return a named sub-instance... if channel does not exist, it will be created

                                                  Parameters

                                                  $name
                                                  channel name
                                                  $config
                                                  channel specific configuration

                                                  Return Value

                                                  bdk\Debug
                                                  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 instancedebug.log, debug.objAbstractStart, and debug.objAbstractEnd 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

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

                                                    Retrieve a configuration value

                                                    Parameters

                                                    $path
                                                    what to get

                                                    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

                                                      • output = true
                                                      • route = html
                                                      • errorEmailer.emailMin = null
                                                      getHeaders()

                                                      Get and clear debug headers that need to be output

                                                      Return Value

                                                      array
                                                      headerName => value array

                                                      By default, response headers (ie generated by chromeLogger, FirePHP, or serverLog) 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)
                                                          \bdk\Debug::varDump($headers);
                                                          var_dump($headers);
                                                      
                                                          foreach ($headers as $nameAndValue) {
                                                              header($nameAndValue[0].': '.$nameAndValue[1]);
                                                          }
                                                      }, -1);
                                                      $debug->log('hello world');
                                                      Example Output
                                                      /path/to/mypage.inc.php(25):
                                                      array (size=1)
                                                        0 => array (size=2)
                                                            0 => string 'X-ChromeLogger-Data' (length=19)
                                                            1 => string 'eyJ2ZXJzaW9uIjoiMy4yIiwiY29sdW1ucyI6WyJsb2ciLCJiYWNrdHJhY2UiLCJ0eXBlIl0sInJvd3MiOltbWyJQSFAiLCJHRVQgaHR0cHM6Ly9sb2NhbC5icmFka2VudC5jb20vcGhwL2RlYnVnLzIuMz9jbGVhckNhY2hlIl0sbnVsbCwiZ3JvdXBDb2xsYXBzZWQiXSxbWyJoZWxsbyB3b3JsZCJdLG51bGwsIiJdLFtbXSxudWxsLCJncm91cEVuZCJdXX0=' (length=268)
                                                      
                                                      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

                                                      If output config value is false, null will be returned.

                                                      Note: Log output is handled automatically, and calling output is gnerally not necessary.

                                                      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

                                                        • hello world
                                                        Changelog:
                                                        • v2.3: $config parameter
                                                        • v1.2: explicitly calling output() is no longer necessary.. log will be output automatically via shutdown function
                                                        setCfg(string|array $path[, mixed $value = null[, int $options = 0]])

                                                        Set one or more config values

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

                                                        Parameters

                                                        $path
                                                        path
                                                        $value
                                                        value
                                                        $options
                                                        bitmask of CONFIG_NO_PUBLISH, CONFIG_NO_RETURN

                                                        Return Value

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

                                                        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

                                                          • User Deprecated: trustyOldFunction's days are numbered. Use superNewFunction instead., /path/to/mypage.inc.php (line 1, eval'd line 20)
                                                          • lastError =
                                                            bdk\ErrorHandler\Error
                                                            extends
                                                            bdk\PubSub\Event
                                                            bdk\PubSub\ValueStore
                                                            implements
                                                            • ArrayAccess
                                                            • IteratorAggregate
                                                              • Traversable
                                                            • JsonSerializable
                                                            • Serializable
                                                            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)
                                                            magic array context
                                                            magic array trace
                                                            protected array|false|null backtrace = null
                                                            protected static errCategories = array(
                                                            • deprecated=>array(
                                                              • 0=>8192
                                                              • 1=>16384
                                                              )
                                                            • error=>array(
                                                              • 0=>256
                                                              • 1=>4096
                                                              )
                                                            • fatal=>array(
                                                              • 0=>1
                                                              • 1=>4
                                                              • 2=>64
                                                              • 3=>16
                                                              )
                                                            • notice=>array(
                                                              • 0=>8
                                                              • 1=>1024
                                                              )
                                                            • strict=>array(
                                                              • 0=>2048
                                                              )
                                                            • warning=>array(
                                                              • 0=>2
                                                              • 1=>32
                                                              • 2=>128
                                                              • 3=>512
                                                              )
                                                            )
                                                            protected static errTypes = array(
                                                            • 32767=>E_ALL
                                                            • 64=>Compile Error
                                                            • 128=>Compile Warning
                                                            • 16=>Core Error
                                                            • 32=>Core Warning
                                                            • 8192=>Deprecated
                                                            • 1=>Fatal Error
                                                            • 8=>Notice
                                                            • 4=>Parsing Error
                                                            • 4096=>Recoverable Error
                                                            • 2048=>Strict
                                                            • 16384=>User Deprecated
                                                            • 256=>User Error
                                                            • 1024=>User Notice
                                                            • 512=>User Warning
                                                            • 2=>Warning
                                                            )
                                                            protected mixed subject = bdk\ErrorHandler
                                                            protected static userErrors = array(
                                                            • 0=>16384
                                                            • 1=>256
                                                            • 2=>1024
                                                            • 3=>512
                                                            )
                                                            protected array values = array(
                                                            • type=>16384
                                                            • message=>trustyOldFunction's days are numbered. Use superNewFunction instead.
                                                            • evalLine=>20
                                                            • 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
                                                              )
                                                            • category=>deprecated
                                                            • continueToNormal=>false
                                                            • continueToPrevHandler=>true
                                                            • exception=>null
                                                            • hash=>0ebafcdb73f3c8a488f5a418fb5e1bad
                                                            • isFirstOccur=>true
                                                            • isHtml=>false
                                                            • isSuppressed=>false
                                                            • throw=>false
                                                            • typeStr=>User Deprecated
                                                            • stats=>array(
                                                              • email=>array(
                                                                • countSince=>0
                                                                • emailedTo=>null
                                                                • timestamp=>null
                                                                )
                                                              • count=>1
                                                              • tsAdded=>1703048757
                                                              • tsLastOccur=>null
                                                              )
                                                            • email=>false
                                                            • inConsole=>true
                                                            )
                                                            private bool propagationStopped = true
                                                            methods
                                                            public __construct(ErrorHandler $errHandler, array $values)
                                                            public __debugInfo(): array
                                                            public __serialize(): array
                                                            public __unserialize(array $data): void
                                                            public asException(): Exception|ErrorException
                                                            public getContext(): array|false
                                                            public getFileAndLine(): string
                                                            public getIterator(): ArrayIterator
                                                            public getMessageHtml(): string
                                                            public getMessageText(): string
                                                            public getSubject(): mixed
                                                            public getTrace(bool|auto $withContext = auto): array|false|null
                                                            public getValue(string $key): mixed
                                                            public getValues(): array
                                                            public hasValue(string $key): bool
                                                            public isFatal(): bool
                                                            public isPropagationStopped(): bool
                                                            public jsonSerialize(): array
                                                            public log(): bool
                                                            public offsetExists(string $key): bool
                                                            public offsetGet(string $key): mixed
                                                            public offsetSet(string $key, mixed $value): void
                                                            public offsetUnset(string $key): void
                                                            public serialize(): string
                                                            public setValue(string $key, mixed $value): $this
                                                            public setValues(array $values = array()): $this
                                                            public stopPropagation(): void
                                                            public static typeStr(int $type): string
                                                            public unserialize(string $data): void
                                                            protected static getCategory(int $errType): string|null
                                                            protected hash(): string
                                                            protected onSet(array $values = array()): void
                                                            private assertValues(array $values): void
                                                            private isHtml(): bool
                                                            private isSuppressed(bdk\ErrorHandler\Error|null $prevOccurrence = null): bool
                                                            private setContinueToNormal(bool $isSuppressed, bool $isFirstOccurrence): bool
                                                            private setValuesInit(array $values): void

                                                          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
                                                          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' (or true) - log sent if there was an error masked by the errorHandler.emailMask config value
                                                          • 'always' - log always sent (if not otherwise output)
                                                          requires collect to also be true
                                                          (we can't email what we don't collect)
                                                          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 facilitate 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
                                                          file

                                                          null

                                                          If a valid filepath, log entries to the file. This will supplement the log that is output via output()

                                                          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

                                                          logEnvInfo
                                                          array(
                                                              'cookies' => true,
                                                              'headers' => true,        // request headers
                                                              'phpInfo' => true,        // PHP_VERSION, ini file locations, memoryLimit, etc
                                                              'post' => true,           // $_POST (or request body), &amp; $_FILES
                                                              'serverVals' => true,     // $_SERVER values specified by logServerKeys
                                                          )

                                                          Specify "environment" information to automatically log.

                                                          Also accepts true (all), or false (none), or string[].

                                                          Example
                                                          Example Source
                                                          $debug = new \bdk\Debug(array(
                                                          	'collect' => true,
                                                          	'output' => true,
                                                          	'logEnvInfo' => true, // this is the default (all other examples use `false`)
                                                          ));
                                                          $debug->info('Not all $_SERVER values are output -> only those included in `logServerKeys', $debug->meta('channel', 'php'));
                                                          Example Output
                                                          PHPDebugConsole


                                                                • Not all $_SERVER values are output -> only those included in `logServerKeys

                                                                  • bdk\PubSub\Event
                                                                    extends
                                                                    bdk\PubSub\ValueStore
                                                                    implements
                                                                    • Serializable
                                                                    • JsonSerializable
                                                                    • IteratorAggregate
                                                                      • Traversable
                                                                    • ArrayAccess
                                                                    properties (via __debugInfo)
                                                                    protected mixed subject = bdk\Debug
                                                                    protected array values = array()
                                                                    private bool propagationStopped = false
                                                                    methods
                                                                    public __construct(mixed $subject = null, array $values = array())
                                                                    public __debugInfo(): array
                                                                    public __serialize(): array
                                                                    public __unserialize(array $data): void
                                                                    public getIterator(): ArrayIterator
                                                                    public getSubject(): mixed
                                                                    public getValue(string $key): mixed
                                                                    public getValues(): array
                                                                    public hasValue(string $key): bool
                                                                    public isPropagationStopped(): bool
                                                                    public jsonSerialize(): array
                                                                    public offsetExists(string $key): bool
                                                                    public offsetGet(string $key): mixed
                                                                    public offsetSet(string $key, mixed $value): void
                                                                    public offsetUnset(string $key): void
                                                                    public serialize(): string
                                                                    public setValue(string $key, mixed $value): $this
                                                                    public setValues(array $values = array()): $this
                                                                    public stopPropagation(): void
                                                                    public unserialize(string $data): void
                                                                    protected onSet(array $values = array()): void

                                                                  ChangeLog:

                                                                  • v2.3: accepts array in addition to boolean
                                                                  • v2.0: introduced
                                                                  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 invoked 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 invoked before entry added to log.
                                                                  • Callback will receive a single param: \bdk\PubSub\Event $event.
                                                                  • Shortcut for subscribing to debug.log event

                                                                  ChangeLog:

                                                                  • v2.0: introduced
                                                                  • v2.0.1: replaces previous onLog value (rather than add additional subscriber)
                                                                  • v3.0: callable receives a \bdk\Debug\LogEntry object (extends \bdk\PubSub\Event)
                                                                  onOutput

                                                                  null

                                                                  • A callable to be invoked before log is output.
                                                                  • Callback will receive a single param: \bdk\PubSub\Event $event.
                                                                  • Shortcut for subscribing to debug.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

                                                                  output related options

                                                                  These options deal with how the log is output

                                                                  outputAs

                                                                  null

                                                                  • With the default value (null), output will be determined based on request / response
                                                                    • "html" if non-ajax, Content-Type: html is being output
                                                                    • outputAsHonHtml 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
                                                                    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
                                                                    script
                                                                    • Outputs the log as <script></script> containing console.xxx calls
                                                                    • 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\PluginInterface
                                                                  outputAsDefaultNonHtml

                                                                  chromeLogger

                                                                  If outputAs is null, this value will be used for http requests that are ajax or non-html response

                                                                  outputHeaders

                                                                  true

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

                                                                  ChangeLog:

                                                                  • v3.0: output buffering automatically invoked if using route that outputs headers
                                                                  • v2.3: introduced
                                                                  html related options
                                                                  addBR

                                                                  false

                                                                  Convert "\n" to "<br />\n" in strings?

                                                                  • unnecessary if styling with white-space: pre (as base css does)
                                                                  css

                                                                  Supplemental CSS to output

                                                                  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?

                                                                  object logging & output options

                                                                  These options deal specifically with debugging objects

                                                                  objectsExclude

                                                                  array("DOMNode","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

                                                                  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
                                                                  collectConstants

                                                                  true

                                                                  Whether to collect object constants

                                                                  outputConstants

                                                                  true

                                                                  Whether to output object's constants

                                                                  collectMethods

                                                                  true

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

                                                                  outputMethods

                                                                  true

                                                                  Whether to output object's methods

                                                                  cacheMethods

                                                                  true

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

                                                                  The need to disable this is extremely rare

                                                                  outputMethodDescription

                                                                  true

                                                                  Whether to output method's long phpDoc description

                                                                  errorEmailer options
                                                                  • configure how error notifications are emailed
                                                                  • this feature is disabled by default as of v3.0
                                                                  • 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

                                                                  emailThrottleFile

                                                                  __DIR__ . '/error_emails.json'

                                                                  A file used to maintain details of recent errors.

                                                                  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
                                                                  emailThrottledSummary

                                                                  true

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

                                                                  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 defined at a time (our handler publishes a event / unlimited subscribers).
                                                                  • 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).

                                                                  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'].
                                                                  • continueToNormal true: log the error
                                                                  • continueToNormal false: continue without logging
                                                                  See errorHandler.error event

                                                                  ChangeLog:

                                                                  • v2.1: introduced
                                                                  onError

                                                                  null

                                                                  A callable to be invoked when error occurs.

                                                                  • Shortcut for subscribing to errorHandler.error event
                                                                  • Will also get called on fatal errors.
                                                                  • Callback will receive a single param: \bdk\PubSub\Event $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)

                                                                  Events

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

                                                                  debug.bootstrap

                                                                  published when debug is instantiated

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

                                                                  published when config is updated

                                                                  • Call $event->getSubject() to get the debug object
                                                                  • $event['config'] contains the changed config values
                                                                  Changelog:
                                                                  • v2.1 - 'config' value added
                                                                  • v2.0 - introduced
                                                                  debug.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:
                                                                  • v3.0 - $event['appendLog'] instead of $event->stopPropagation() to control whether to log
                                                                  • v2.1 - publish when calling inaccessible method (custom methods)
                                                                  • v2.0 - introduced
                                                                  debug.objAbstractEnd

                                                                  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
                                                                  debug.objAbstractStart

                                                                  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 debug.objAbstractStart 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`
                                                                  debug.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

                                                                  debug.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).

                                                                  • debug.log is published when you call a debug method.
                                                                  • debug.outputLogEntry 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['route'] = output "plugin" instance (ie the OutputHtml object)
                                                                  Changelog:
                                                                  • v2.1.1 - add the return value
                                                                  • v2.1 - introduced
                                                                  errorHandler.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
                                                                  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

                                                                  Output "Plugins"

                                                                  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: getHeaders

                                                                  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.

                                                                  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: getHeaders

                                                                  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:

                                                                  PSR-3 Logger

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

                                                                  PHPDebugLogger doesn't include psr/log or monolog/monolog... install separately if needed.
                                                                  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

                                                                    • This thing does it all
                                                                    • I literally can't even
                                                                    Example Source
                                                                    $monolog = new \Monolog\Logger('PHPDebugConsole');
                                                                    $monolog->pushHandler(new \Monolog\Handler\PsrHandler($debug->logger));
                                                                    $monolog->info('yup, it works');
                                                                    Example Output

                                                                      • yup, it works
                                                                      Changelog:
                                                                      • v2.3

                                                                      Changelog

                                                                      v3.2 – Coming soon

                                                                      • objectSort config is now a space separated list with (default = "inheritance visibility name")
                                                                      • Implements now stored as a structure that conveys interface inheritance
                                                                      • What interfaces a method implements are now collected for every implemented interface (prev a select few such as ArrayAccess)
                                                                      • new config options: methodStaticVarCollect & methodStaticVarOutput
                                                                      • anonymous objects now collected & stored like other objects… collecting attribues, phpDoc, & interfaces in the process
                                                                      • html output :
                                                                        • display icon on methods implementing an interface (hover for more info)
                                                                        • display phpDoc @throws info
                                                                        • no longer add "inherited" classname to methods/properties/constants (redundant to data-inherited-from attribute)
                                                                        • properties/methods now grouped by inheritance by default. (dependant on "objectSort" first sorted by 'inheritance')
                                                                        • new interfacesCollapse config
                                                                        • new objectSectionOrder config.
                                                                          defaults to ['attributes', 'extends', 'implements', 'constants', 'cases', 'properties', 'methods', 'phpDoc']

                                                                      v3.1.2 – 2023-12-19

                                                                      • Debug::varDump() not escaping special chars
                                                                      • Utility/Php::getIniFiles() not properly handling empty return from php_ini_scanned_files()
                                                                      • ErrorHandler::handleException() - check headers_sent() before calling http_response_code(500)

                                                                      v3.1.1 – 2023-12-06

                                                                      • LogRequest - not "parsing" content-type correctly / not displaying $_POST values (ie for multipart/form-data)
                                                                      • ReqRes::getResponseHeaders() merging default headers without regards to header case insensitivity leading to default Content-Type being added in addition to "Content-type" etc ... ReqRes::getResponseHeader('Content-Type') getting the default value. (only affects debug output)
                                                                      • HttpMessage\ServerRequest::fromGlobals() now has $parseStrOpts param
                                                                      • HttpMessage\Uri::fromGlobals() is now a public static method

                                                                      v3.1 – 2023-11-18

                                                                      • New Discord route (for errors)
                                                                      • New Slack route (for errors)
                                                                      • New Teams route (for errors)
                                                                      • New varDump static method for in-place var_dump-like debugging
                                                                      • Objects
                                                                        • Overhaul object abstraction for more efficient collection / storage / serialization / transmission of data
                                                                        • Collect (and display) php 8.2's class-level readOnly modifier
                                                                        • Added visual callouts to dynamic properties
                                                                        • Added visual callouts to constants/properties/methods that override ancestor
                                                                      • New maxDepth option
                                                                      • New Utility/Reflection class
                                                                      • Internals
                                                                        • Move more functionality / features / methods to plugins
                                                                          all debug methods, "auto route", runtime-values
                                                                        • Cleanup bootstrap process
                                                                        • Move phpdoc type resolution to phpdoc parser.
                                                                      • Underscore prefix no longer required to call most methods statically
                                                                        \bdk\Debug::log('this is new') and \bdk\Debug::_log('still works')

                                                                      v3.0.7 – 2023-11-18

                                                                      • official PHP 8.3 support
                                                                      • small javascript ui fixes

                                                                      v3.0.5 / v3.0.6 – 2023-10-11

                                                                      • Error may occur in certain scenarios when setting config via meta param / Abstracter not yet initialized
                                                                      • Monolog handler - now compatible with monolog v1 - v3

                                                                      v3.0.4 – 2023-05-29

                                                                      • Add more redaction to collectors (Guzzle Request Target / Oauth signature)
                                                                      • StatementInfo (MySqli, Doctrine, PDO) - don't truncate SQL statement (ignore stringMaxLen)
                                                                      • improve UriUtils::parseUrl()
                                                                      • wamp route sending null meta values
                                                                      • bump bundled PrismJS to latest
                                                                      • other minor fixes
                                                                      • coding standards

                                                                      v3.0.3 – 2023-02-04

                                                                      • Non-composer autoloader doesn't load main Debug class! (facepalm)
                                                                      • nested channels ignore their output config value.
                                                                      • restore non-sidebar channel filter/toggles functionality (used by documentation)
                                                                      • minor regression with base64-encoded strings' flat-tab html output
                                                                      • Add unit tests for MonologHandler, & PhpCurlClass collector

                                                                      v3.0.2 – 2023-01-13

                                                                      • Guzzle middleware tweaks
                                                                      • SoapClient collector improvements
                                                                      • Yii 1.1 tweaks
                                                                      • Declare closures as static when possible
                                                                      • Tweak phpcs rules
                                                                      • Encoded strings.. Don't nest tabs / refactor w/ new HtmlStringEncoded class
                                                                      • Redact basic password from URLs

                                                                      v3.0.1 – 2022-11-14

                                                                      • HttpMessage\Uri::withScheme -> allow empty value
                                                                      • bdk\Debug\Psr3\Logger (psr3 implemenation) is now compatible with psr/log v1, v2, & v3
                                                                      • FindExit error when exit/Fatal from static method
                                                                      • Don't attempt to resolve complex array doctypes
                                                                      • GuzzleMiddleware tweaks
                                                                      • new HttpMessage\UriUtils class

                                                                      v3.0 – 2022-10-14

                                                                      • 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
                                                                      • PHP 8.1 : Enum support
                                                                      • PHP 8.2 : #[\SensitiveParameter] support
                                                                      • ErrorHandler v3
                                                                        • New Error class (extends generic Event) replaces array
                                                                        • Error notifications no longer emailed by default (see new enableEmailer config option)
                                                                      • Included decorators/helpers for logging PDO, mysqli, Doctrine, Guzzle, Curl, OAuth, SimpleCache, Soap, Twig, SwiftMailer
                                                                      • MiddlewareInterface (PSR-15), & new writeToResponse() method (PSR-7)
                                                                      • 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
                                                                      Fork me on GitHub