PHPDebugConsole is a browser/javascript like console class for PHP (logging, debugging, value inspecting, etc).
city | state | population | |
---|---|---|---|
0 | Atlanta | GA | 472522 |
1 | Buffalo | NY | 256902 |
2 | Chicago | IL | 2704958 |
3 | Denver | CO | 693060 |
4 | Seattle | WA | 704352 |
5 | Tulsa | OK | 403090 |
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
<?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');
$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');
alert(string $message[, string $level = error[, bool $dismissible = false]]): static
Display an alert at the top of the log
false
) Whether to display a close icon/buttonCan use styling & substitutions.
If using substitutions will need to pass $level
& $dismissible
as meta values
$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,
)));
assert(bool $assertion[, mixed …$msg = null]): Debug
If first argument evaluates false
, log the remaining parameters
$debug->assert(1 + 1 === 2, 'basic addition');
$debug->assert(1 * 1 === 2, 'basic multiplication');
$debug->assert(false); // no message parameter
log()
for examples
clear(int $bitmask = bdk\Debug::CLEAR_LOG): Debug
Clear the log
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 entrycollect
is false
$debug->log('now you see me');
$debug->error('yikes, I\'m an error');
$debug->clear();
$debug->info('hover over "cleared" entry for file & line');
count(mixed $label = null[, int $flags = null]): static
count(int $flags): static
Log the number of times this has been called with the given label.
count()
has been called at this particular line.\bdk\Debug::COUNT_NO_INC
: don't increment the counter
(ie, just get the current count)
\bdk\Debug::COUNT_NO_OUT
: don't output/logCOUNT_NO_INC
)collect
is false
If collect
= false
, count()
will be performed "silently"$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
$flags
argument addedcountReset(mixed $label = null[, int $flags = null]): static
countReset(int $flags): static
Resets the counter
collect
is false
).$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');
error(mixed …$arg): Debug
Log an error message.
$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');
log()
for examples
htmlspecialchars()
is not applied to first argument
$debug->error('unsanitized user input', $_GET['whatever']);
$debug->error($_GET['whatever']);
This behavior will not exist in v3.0
group(mixed …$arg): Debug
Create a new inline group
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 |
groupEnd()
.$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;
}
groupCollapsed(mixed …$arg): Debug
Create a new inline group
Unlike group()
, groupCollapsed()
, will initially be collapsed
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 |
groupEnd()
.groupCollapsed()
will be expanded if it contains a nested error or warn, or if groupUncollapse()
was used
$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;
}
groupEnd(mixed $value = bdk\Debug\Abstracter::UNDEFINED): Debug
Close current group
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.
$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;
}
$value
parametergroupSummary(int $priority = 0): Debug
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
$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');
groupUncollapse(): Debug
Uncollapse ancestor groups
This will only occur if cfg['collect']
is currently true
error()
, warn()
, and any errors will also uncollapse groups
$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();
info(mixed …$arg): Debug
Log some informative information
$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');
log()
for examples
htmlspecialchars()
is not applied to first argument
$debug->info('unsanitized user input', $_GET['whatever']);
$debug->info($_GET['whatever']);
This behavior will not exist in v3.0
log(mixed …$arg): Debug
Log general information
$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 & 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);
htmlspecialchars()
is not applied to first argument
$debug->log('unsanitized user input', $_GET['whatever']);
$debug->log($_GET['whatever']);
This behavior will not exist in v3.0
profile(string $name = null): Debug
Starts recording a performance profile
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)true
before using profile()
… declare(ticks=1);
into php scripts as they're loaded (by registering a file stream wrapper) / 🧙 sorcery./*
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();
calls | totalTime | ownTime | |
---|---|---|---|
CBaseController::beginWidget | 1 | 0.649757 | 0.016487 |
CModule::__get | 35 | 0.374357 | 0.001115 |
BootActiveForm::inputRow | 34 | 0.372318 | 0.002285 |
BootInput::run | 34 | 0.349555 | 0.005287 |
CModel::getValidators | 131 | 0.305193 | 0.087937 |
CHtml::openTag | 34 | 0.272806 | 0.001669 |
BootInput::getLabel | 27 | 0.24355 | 0.001747 |
BootActiveForm::dropDownListRow | 8 | 0.166388 | 0.000251 |
CListIterator::next | 2851 | 0.162077 | 0.162077 |
CModel::isAttributeRequired | 73 | 0.158948 | 0.005975 |
BootActiveForm::textFieldRow | 18 | 0.158701 | 0.000439 |
CActiveForm::dropDownList | 9 | 0.119784 | 0.000368 |
CHtml::activeDropDownList | 9 | 0.116868 | 0.00125 |
CHtml::tag | 372 | 0.114503 | 0.012069 |
CHtml::resolveValue | 40 | 0.111883 | 0.026433 |
CHtml::renderAttributes | 409 | 0.111258 | 0.111258 |
CActiveForm::textField | 19 | 0.073367 | 0.000563 |
CHtml::activeTextField | 19 | 0.067102 | 0.00162 |
CHtml::activeInputField | 23 | 0.061379 | 0.004848 |
WForm::label | 27 | 0.049011 | 0.002613 |
CModel::createValidators | 1 | 0.041418 | 0.000133 |
BootActiveForm::checkBoxRow | 7 | 0.040609 | 0.000235 |
buildCustField | 3 | 0.037463 | 0.001219 |
AppSettingManager::get | 4 | 0.031354 | 0.000555 |
MyModel::rules | 1 | 0.031099 | 0.000325 |
WForm::resolveArgs | 48 | 0.02797 | 0.010955 |
ValidationRule::model | 1 | 0.025695 | 6.5E-5 |
YiiBase::log | 16 | 0.025059 | 0.004995 |
CList::getIterator | 151 | 0.022166 | 0.005364 |
CLogger::log | 16 | 0.020065 | 0.002577 |
CComponent::__get | 35 | 0.019456 | 0.002591 |
CDbCommand::getText | 16 | 0.019184 | 0.00109 |
WForm::checkBox | 7 | 0.018922 | 0.000215 |
CActiveForm::label | 27 | 0.018192 | 0.001984 |
CActiveRecord::model | 1 | 0.017852 | 9.1E-5 |
CLogger::flush | 16 | 0.017488 | 0.001229 |
CListIterator::__construct | 151 | 0.016802 | 0.016802 |
AccessManager::isAllowed | 2 | 0.016774 | 0.000702 |
include | 18 | 0.016472 | 0.010252 |
CEvent::__construct | 16 | 0.016259 | 0.001548 |
CHtml::activeLabel | 27 | 0.016208 | 0.004621 |
CActiveRecordMetaData::__construct | 1 | 0.016178 | 0.000325 |
CActiveForm::checkBox | 7 | 0.015875 | 0.000245 |
CDbSchema::getTable | 1 | 0.015853 | 0.000114 |
CMysqlSchema::loadTable | 1 | 0.015739 | 6.8E-5 |
CMysqlSchema::findColumns | 1 | 0.015562 | 0.000515 |
CActiveRecord::query | 2 | 0.015192 | 0.000198 |
WForm::resolveName | 99 | 0.014746 | 0.014746 |
CComponent::raiseEvent | 16 | 0.014711 | 0.00158 |
CDbConnection::createCommand | 4 | 0.013827 | 0.000416 |
CWidgetFactory::createWidget | 34 | 0.013604 | 0.009948 |
CDbCommand::queryRow | 2 | 0.012391 | 0.000661 |
CDbCommand::__construct | 4 | 0.012241 | 0.001517 |
CModule::getComponent | 2 | 0.011787 | 0.000314 |
AccessRole::isAllowed | 10 | 0.01173 | 0.000417 |
CHtml::label | 27 | 0.011587 | 0.003098 |
SAML2_autoload | 8 | 0.011458 | 0.00304 |
BootActiveForm::error | 34 | 0.010859 | 0.006517 |
CHtml::activeCheckBox | 7 | 0.01053 | 0.000966 |
CDbCommand::queryInternal | 2 | 0.010479 | 0.001404 |
ValidationRuleManager::findOptionsByModel | 1 | 0.010283 | 3.9E-5 |
CValidator::createValidator | 20 | 0.010067 | 0.004505 |
WForm::hiddenField | 4 | 0.009578 | 0.000119 |
CLogRouter::collectLogs | 16 | 0.009528 | 0.003129 |
CActiveRecord::find | 1 | 0.00926 | 6.0E-5 |
spl_autoload_call | 6 | 0.009063 | 0.000206 |
YiiBase::import | 10 | 0.008899 | 0.001484 |
CBaseController::createWidget | 1 | 0.008895 | 2.8E-5 |
CHtml::hiddenField | 8 | 0.008433 | 0.000782 |
WForm::resolveModel | 56 | 0.007834 | 0.007834 |
CWebApplication::getWidgetFactory | 1 | 0.00769 | 9.8E-5 |
BootActiveForm::checkBoxListRow | 1 | 0.007569 | 2.4E-5 |
YiiBase::autoload | 8 | 0.00752 | 0.000231 |
WebUser::__get | 12 | 0.007343 | 0.000347 |
CLogRoute::collectLogs | 32 | 0.006399 | 0.00285 |
AccessRule::match | 10 | 0.006349 | 0.002645 |
WForm::resolveAttribute | 101 | 0.005955 | 0.005955 |
CHtml::inputField | 11 | 0.005829 | 0.001498 |
CHtml::resolveNameID | 40 | 0.005624 | 0.005476 |
YiiBase::trace | 3 | 0.005579 | 0.000144 |
WebUser::_getModel | 20 | 0.00544 | 0.00057 |
CWebUser::__get | 20 | 0.00526 | 0.000473 |
ActiveRecord::__get | 65 | 0.005229 | 0.004732 |
BootActiveForm::checkBoxList | 1 | 0.005145 | 3.3E-5 |
WebUser::getState | 39 | 0.005063 | 0.001931 |
CWebUser::hasState | 20 | 0.004787 | 0.001617 |
BootActiveForm::inputsList | 1 | 0.004415 | 0.000679 |
BootActiveForm::getErrorHtml | 34 | 0.004342 | 0.002017 |
AppSettingManager::arrayPath | 18 | 0.004308 | 0.004308 |
YiiBase::getPathOfAlias | 3 | 0.00393 | 0.001696 |
WForm::resolveLabel | 27 | 0.00362 | 0.001737 |
CLogger::getLogs | 32 | 0.00355 | 0.00355 |
BootInput::init | 34 | 0.003261 | 0.003261 |
CWebUser::getIsGuest | 20 | 0.003258 | 0.000518 |
YiiBase::createComponent | 2 | 0.003253 | 0.000316 |
WForm::textField | 1 | 0.003244 | 6.1E-5 |
CActiveForm::hiddenField | 4 | 0.003178 | 0.000103 |
CWebUser::getState | 39 | 0.003132 | 0.003132 |
CHtml::activeHiddenField | 4 | 0.003075 | 0.000293 |
WForm::dropDownList | 1 | 0.00305 | 4.9E-5 |
CActiveRecord::getAttributeLabel | 43 | 0.003 | 0.003 |
CHtml::checkBox | 3 | 0.002953 | 0.000686 |
CHtml::resolveName | 43 | 0.00294 | 0.00294 |
AccessManager::_getUserRole | 2 | 0.002468 | 8.8E-5 |
CMysqlSchema::createColumn | 4 | 0.002414 | 0.000723 |
WebUser::getDefaultRoleContexts | 10 | 0.002269 | 0.000245 |
CDbCommandBuilder::createFindCommand | 2 | 0.002099 | 0.000552 |
WebUser::getAllowedRoles | 10 | 0.002024 | 0.000743 |
CWidget::__construct | 34 | 0.001952 | 0.001952 |
CDbColumnSchema::init | 5 | 0.001798 | 0.000444 |
CComponent::__isset | 20 | 0.001612 | 0.001612 |
BootActiveForm::init | 1 | 0.001177 | 6.9E-5 |
CList::insertAt | 21 | 0.001117 | 0.001117 |
CActiveForm::init | 1 | 0.001108 | 4.6E-5 |
CHtml::beginForm | 1 | 0.000997 | 0.000139 |
WebUser::getDefaultRole | 10 | 0.000902 | 0.000247 |
CHtml::normalizeUrl | 1 | 0.000858 | 6.8E-5 |
CMysqlColumnSchema::extractLimit | 5 | 0.000796 | 0.000165 |
CDbCommand::prepare | 6 | 0.000679 | 0.000385 |
CDbColumnSchema::extractLimit | 5 | 0.000631 | 0.000631 |
ValidationRule::afterFind | 2 | 0.000612 | 6.0E-5 |
CDbCommand::setText | 4 | 0.000514 | 0.000267 |
CDbCommand::bindValue | 2 | 0.000508 | 0.000105 |
CDbCriteria::compare | 2 | 0.000501 | 0.000357 |
CActiveRecord::getPrimaryKey | 2 | 0.000328 | 0.000189 |
call_user_func | 2 | 0.000328 | 5.5E-5 |
CActiveRecord::applyScopes | 2 | 0.000313 | 0.000134 |
CMysqlColumnSchema::extractType | 5 | 0.000311 | 0.000311 |
CDbSchema::quoteColumnName | 5 | 0.000283 | 0.000283 |
MyModel::getReferenceName | 2 | 0.000273 | 6.3E-5 |
CDbConnection::setActive | 4 | 0.000272 | 0.000272 |
CComponent::hasEventHandler | 4 | 0.000263 | 0.000263 |
CDbCommand::cancel | 4 | 0.000247 | 0.000247 |
CMysqlColumnSchema::extractDefault | 2 | 0.000247 | 5.7E-5 |
CApplicationComponent::init | 2 | 0.000219 | 9.3E-5 |
CComponent::__set | 2 | 0.000213 | 0.000108 |
CDbCommandBuilder::applyLimit | 2 | 0.000196 | 0.000196 |
ActiveRecord::init | 2 | 0.000195 | 5.9E-5 |
CActiveRecord::beforeFind | 2 | 0.000191 | 5.4E-5 |
CDbColumnSchema::extractDefault | 2 | 0.00019 | 9.6E-5 |
CActiveRecord::afterFind | 2 | 0.000183 | 5.7E-5 |
CActiveRecord::getDbCriteria | 2 | 0.000179 | 0.000179 |
CComponent::attachBehaviors | 3 | 0.000178 | 0.000178 |
CActiveRecord::setAttribute | 2 | 0.000169 | 0.000169 |
CDbCommandBuilder::ensureTable | 2 | 0.000157 | 0.000157 |
CWidgetFactory::init | 1 | 0.000151 | 4.2E-5 |
CDbCriteria::addCondition | 2 | 0.000144 | 0.000144 |
ActiveRecord::attachEvents | 2 | 0.000136 | 0.000136 |
CDbCommandBuilder::createCriteria | 2 | 0.000132 | 0.000132 |
CList::__construct | 1 | 0.00012 | 7.2E-5 |
CDbConnection::getPdoType | 2 | 0.000119 | 0.000119 |
CModel::setScenario | 2 | 0.000116 | 0.000116 |
CMysqlSchema::resolveTableNames | 1 | 0.000109 | 0.000109 |
usort | 1 | 0.000104 | 2.2E-5 |
CHttpRequest::getUrl | 1 | 9.8E-5 | 2.5E-5 |
CDbColumnSchema::typecast | 1 | 9.4E-5 | 9.4E-5 |
{closure} | 1 | 8.2E-5 | 8.2E-5 |
CHttpRequest::getRequestUri | 1 | 7.3E-5 | 7.3E-5 |
YiiBase::setPathOfAlias | 1 | 6.4E-5 | 6.4E-5 |
CDbCriteria::__construct | 1 | 6.1E-5 | 6.1E-5 |
uniqueMultiColumnValidator::setCaseSensitiveAttr | 1 | 5.5E-5 | 5.5E-5 |
CWidget::setId | 1 | 5.0E-5 | 5.0E-5 |
CList::setReadOnly | 1 | 4.8E-5 | 4.8E-5 |
0.649763 |
profileEnd(string $name = null): Debug
Stops recording profile info & adds info to the log
/*
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();
calls | totalTime | ownTime | |
---|---|---|---|
CBaseController::beginWidget | 1 | 0.649757 | 0.016487 |
CModule::__get | 35 | 0.374357 | 0.001115 |
BootActiveForm::inputRow | 34 | 0.372318 | 0.002285 |
BootInput::run | 34 | 0.349555 | 0.005287 |
CModel::getValidators | 131 | 0.305193 | 0.087937 |
CHtml::openTag | 34 | 0.272806 | 0.001669 |
BootInput::getLabel | 27 | 0.24355 | 0.001747 |
BootActiveForm::dropDownListRow | 8 | 0.166388 | 0.000251 |
CListIterator::next | 2851 | 0.162077 | 0.162077 |
CModel::isAttributeRequired | 73 | 0.158948 | 0.005975 |
BootActiveForm::textFieldRow | 18 | 0.158701 | 0.000439 |
CActiveForm::dropDownList | 9 | 0.119784 | 0.000368 |
CHtml::activeDropDownList | 9 | 0.116868 | 0.00125 |
CHtml::tag | 372 | 0.114503 | 0.012069 |
CHtml::resolveValue | 40 | 0.111883 | 0.026433 |
CHtml::renderAttributes | 409 | 0.111258 | 0.111258 |
CActiveForm::textField | 19 | 0.073367 | 0.000563 |
CHtml::activeTextField | 19 | 0.067102 | 0.00162 |
CHtml::activeInputField | 23 | 0.061379 | 0.004848 |
WForm::label | 27 | 0.049011 | 0.002613 |
CModel::createValidators | 1 | 0.041418 | 0.000133 |
BootActiveForm::checkBoxRow | 7 | 0.040609 | 0.000235 |
buildCustField | 3 | 0.037463 | 0.001219 |
AppSettingManager::get | 4 | 0.031354 | 0.000555 |
MyModel::rules | 1 | 0.031099 | 0.000325 |
WForm::resolveArgs | 48 | 0.02797 | 0.010955 |
ValidationRule::model | 1 | 0.025695 | 6.5E-5 |
YiiBase::log | 16 | 0.025059 | 0.004995 |
CList::getIterator | 151 | 0.022166 | 0.005364 |
CLogger::log | 16 | 0.020065 | 0.002577 |
CComponent::__get | 35 | 0.019456 | 0.002591 |
CDbCommand::getText | 16 | 0.019184 | 0.00109 |
WForm::checkBox | 7 | 0.018922 | 0.000215 |
CActiveForm::label | 27 | 0.018192 | 0.001984 |
CActiveRecord::model | 1 | 0.017852 | 9.1E-5 |
CLogger::flush | 16 | 0.017488 | 0.001229 |
CListIterator::__construct | 151 | 0.016802 | 0.016802 |
AccessManager::isAllowed | 2 | 0.016774 | 0.000702 |
include | 18 | 0.016472 | 0.010252 |
CEvent::__construct | 16 | 0.016259 | 0.001548 |
CHtml::activeLabel | 27 | 0.016208 | 0.004621 |
CActiveRecordMetaData::__construct | 1 | 0.016178 | 0.000325 |
CActiveForm::checkBox | 7 | 0.015875 | 0.000245 |
CDbSchema::getTable | 1 | 0.015853 | 0.000114 |
CMysqlSchema::loadTable | 1 | 0.015739 | 6.8E-5 |
CMysqlSchema::findColumns | 1 | 0.015562 | 0.000515 |
CActiveRecord::query | 2 | 0.015192 | 0.000198 |
WForm::resolveName | 99 | 0.014746 | 0.014746 |
CComponent::raiseEvent | 16 | 0.014711 | 0.00158 |
CDbConnection::createCommand | 4 | 0.013827 | 0.000416 |
CWidgetFactory::createWidget | 34 | 0.013604 | 0.009948 |
CDbCommand::queryRow | 2 | 0.012391 | 0.000661 |
CDbCommand::__construct | 4 | 0.012241 | 0.001517 |
CModule::getComponent | 2 | 0.011787 | 0.000314 |
AccessRole::isAllowed | 10 | 0.01173 | 0.000417 |
CHtml::label | 27 | 0.011587 | 0.003098 |
SAML2_autoload | 8 | 0.011458 | 0.00304 |
BootActiveForm::error | 34 | 0.010859 | 0.006517 |
CHtml::activeCheckBox | 7 | 0.01053 | 0.000966 |
CDbCommand::queryInternal | 2 | 0.010479 | 0.001404 |
ValidationRuleManager::findOptionsByModel | 1 | 0.010283 | 3.9E-5 |
CValidator::createValidator | 20 | 0.010067 | 0.004505 |
WForm::hiddenField | 4 | 0.009578 | 0.000119 |
CLogRouter::collectLogs | 16 | 0.009528 | 0.003129 |
CActiveRecord::find | 1 | 0.00926 | 6.0E-5 |
spl_autoload_call | 6 | 0.009063 | 0.000206 |
YiiBase::import | 10 | 0.008899 | 0.001484 |
CBaseController::createWidget | 1 | 0.008895 | 2.8E-5 |
CHtml::hiddenField | 8 | 0.008433 | 0.000782 |
WForm::resolveModel | 56 | 0.007834 | 0.007834 |
CWebApplication::getWidgetFactory | 1 | 0.00769 | 9.8E-5 |
BootActiveForm::checkBoxListRow | 1 | 0.007569 | 2.4E-5 |
YiiBase::autoload | 8 | 0.00752 | 0.000231 |
WebUser::__get | 12 | 0.007343 | 0.000347 |
CLogRoute::collectLogs | 32 | 0.006399 | 0.00285 |
AccessRule::match | 10 | 0.006349 | 0.002645 |
WForm::resolveAttribute | 101 | 0.005955 | 0.005955 |
CHtml::inputField | 11 | 0.005829 | 0.001498 |
CHtml::resolveNameID | 40 | 0.005624 | 0.005476 |
YiiBase::trace | 3 | 0.005579 | 0.000144 |
WebUser::_getModel | 20 | 0.00544 | 0.00057 |
CWebUser::__get | 20 | 0.00526 | 0.000473 |
ActiveRecord::__get | 65 | 0.005229 | 0.004732 |
BootActiveForm::checkBoxList | 1 | 0.005145 | 3.3E-5 |
WebUser::getState | 39 | 0.005063 | 0.001931 |
CWebUser::hasState | 20 | 0.004787 | 0.001617 |
BootActiveForm::inputsList | 1 | 0.004415 | 0.000679 |
BootActiveForm::getErrorHtml | 34 | 0.004342 | 0.002017 |
AppSettingManager::arrayPath | 18 | 0.004308 | 0.004308 |
YiiBase::getPathOfAlias | 3 | 0.00393 | 0.001696 |
WForm::resolveLabel | 27 | 0.00362 | 0.001737 |
CLogger::getLogs | 32 | 0.00355 | 0.00355 |
BootInput::init | 34 | 0.003261 | 0.003261 |
CWebUser::getIsGuest | 20 | 0.003258 | 0.000518 |
YiiBase::createComponent | 2 | 0.003253 | 0.000316 |
WForm::textField | 1 | 0.003244 | 6.1E-5 |
CActiveForm::hiddenField | 4 | 0.003178 | 0.000103 |
CWebUser::getState | 39 | 0.003132 | 0.003132 |
CHtml::activeHiddenField | 4 | 0.003075 | 0.000293 |
WForm::dropDownList | 1 | 0.00305 | 4.9E-5 |
CActiveRecord::getAttributeLabel | 43 | 0.003 | 0.003 |
CHtml::checkBox | 3 | 0.002953 | 0.000686 |
CHtml::resolveName | 43 | 0.00294 | 0.00294 |
AccessManager::_getUserRole | 2 | 0.002468 | 8.8E-5 |
CMysqlSchema::createColumn | 4 | 0.002414 | 0.000723 |
WebUser::getDefaultRoleContexts | 10 | 0.002269 | 0.000245 |
CDbCommandBuilder::createFindCommand | 2 | 0.002099 | 0.000552 |
WebUser::getAllowedRoles | 10 | 0.002024 | 0.000743 |
CWidget::__construct | 34 | 0.001952 | 0.001952 |
CDbColumnSchema::init | 5 | 0.001798 | 0.000444 |
CComponent::__isset | 20 | 0.001612 | 0.001612 |
BootActiveForm::init | 1 | 0.001177 | 6.9E-5 |
CList::insertAt | 21 | 0.001117 | 0.001117 |
CActiveForm::init | 1 | 0.001108 | 4.6E-5 |
CHtml::beginForm | 1 | 0.000997 | 0.000139 |
WebUser::getDefaultRole | 10 | 0.000902 | 0.000247 |
CHtml::normalizeUrl | 1 | 0.000858 | 6.8E-5 |
CMysqlColumnSchema::extractLimit | 5 | 0.000796 | 0.000165 |
CDbCommand::prepare | 6 | 0.000679 | 0.000385 |
CDbColumnSchema::extractLimit | 5 | 0.000631 | 0.000631 |
ValidationRule::afterFind | 2 | 0.000612 | 6.0E-5 |
CDbCommand::setText | 4 | 0.000514 | 0.000267 |
CDbCommand::bindValue | 2 | 0.000508 | 0.000105 |
CDbCriteria::compare | 2 | 0.000501 | 0.000357 |
CActiveRecord::getPrimaryKey | 2 | 0.000328 | 0.000189 |
call_user_func | 2 | 0.000328 | 5.5E-5 |
CActiveRecord::applyScopes | 2 | 0.000313 | 0.000134 |
CMysqlColumnSchema::extractType | 5 | 0.000311 | 0.000311 |
CDbSchema::quoteColumnName | 5 | 0.000283 | 0.000283 |
MyModel::getReferenceName | 2 | 0.000273 | 6.3E-5 |
CDbConnection::setActive | 4 | 0.000272 | 0.000272 |
CComponent::hasEventHandler | 4 | 0.000263 | 0.000263 |
CDbCommand::cancel | 4 | 0.000247 | 0.000247 |
CMysqlColumnSchema::extractDefault | 2 | 0.000247 | 5.7E-5 |
CApplicationComponent::init | 2 | 0.000219 | 9.3E-5 |
CComponent::__set | 2 | 0.000213 | 0.000108 |
CDbCommandBuilder::applyLimit | 2 | 0.000196 | 0.000196 |
ActiveRecord::init | 2 | 0.000195 | 5.9E-5 |
CActiveRecord::beforeFind | 2 | 0.000191 | 5.4E-5 |
CDbColumnSchema::extractDefault | 2 | 0.00019 | 9.6E-5 |
CActiveRecord::afterFind | 2 | 0.000183 | 5.7E-5 |
CActiveRecord::getDbCriteria | 2 | 0.000179 | 0.000179 |
CComponent::attachBehaviors | 3 | 0.000178 | 0.000178 |
CActiveRecord::setAttribute | 2 | 0.000169 | 0.000169 |
CDbCommandBuilder::ensureTable | 2 | 0.000157 | 0.000157 |
CWidgetFactory::init | 1 | 0.000151 | 4.2E-5 |
CDbCriteria::addCondition | 2 | 0.000144 | 0.000144 |
ActiveRecord::attachEvents | 2 | 0.000136 | 0.000136 |
CDbCommandBuilder::createCriteria | 2 | 0.000132 | 0.000132 |
CList::__construct | 1 | 0.00012 | 7.2E-5 |
CDbConnection::getPdoType | 2 | 0.000119 | 0.000119 |
CModel::setScenario | 2 | 0.000116 | 0.000116 |
CMysqlSchema::resolveTableNames | 1 | 0.000109 | 0.000109 |
usort | 1 | 0.000104 | 2.2E-5 |
CHttpRequest::getUrl | 1 | 9.8E-5 | 2.5E-5 |
CDbColumnSchema::typecast | 1 | 9.4E-5 | 9.4E-5 |
{closure} | 1 | 8.2E-5 | 8.2E-5 |
CHttpRequest::getRequestUri | 1 | 7.3E-5 | 7.3E-5 |
YiiBase::setPathOfAlias | 1 | 6.4E-5 | 6.4E-5 |
CDbCriteria::__construct | 1 | 6.1E-5 | 6.1E-5 |
uniqueMultiColumnValidator::setCaseSensitiveAttr | 1 | 5.5E-5 | 5.5E-5 |
CWidget::setId | 1 | 5.0E-5 | 5.0E-5 |
CList::setReadOnly | 1 | 4.8E-5 | 4.8E-5 |
0.649763 |
table(mixed …$arg): Debug
Output an array or object as a table
Takes up to 3 arguments which may be passed in arbitrary order
totalCols | (array ) columns that should be summed |
---|---|
sortable | (true ) should table be sortable by clicking on headers? |
$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',
));
userId | name | sex | naughty | extracol | |
---|---|---|---|---|---|
0 | 1 | Bob | M | false | |
1 | 10 | Sally | F | true | yes |
2 | 2 | Fred | M | false |
userId | name | sex | |
---|---|---|---|
0 | 1 | Bob | M |
1 | 10 | Sally | F |
2 | 2 | Fred | M |
value | |
---|---|
foo | bar |
slim | jim |
When output as HTML (as above), the table is sortable by clicking on headers.
Traversable
as paramtime(string $label = null, float $duration): bdk\Debug
Start a timer identified by label
Does not append log (unless duration is passed).
Use timeEnd
or timeGet
to get time
$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
timeEnd(string $label = null[, bool|string $returnOrTemplate = %label: %time sec[, int $precision = 4]]): bdk\Debug|float|false
Behaves like a stopwatch.. logs and (optionally) returns running time
timeEnd('label')
will return the same value until unpaused with time('label')
$returnOrTemplate
: if true
, the time will be returned as a float (in seconds) and will not be logged.string
, will be used as the template for the output. Default: "%label: %time sec" (as of v1.3.2)
$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
timeGet(string $label = null[, bool|string $returnOrTemplate = %label: %time sec[, int $precision = 4]]): bdk\Debug|float|false
Log/get the running time without stopping/pausing the timer
false
if specified label does not existqueryDb('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;
}
timeLog(string $label = null[, $args = null]): bdk\Debug
Logs the current value of a timer that was previously started via time()
also logs additional arguments
$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'));
trace(bool $inclContext = false[, string $caption = trace]): Debug
Log a stack trace
Essentially PHP's debug_backtrace()
, but displayed as a table
Params may be passed in any order
false
) Include code snippetfunction 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');
file | line | function | |
---|---|---|---|
0 | /path/to/mypage.inc.php | 7 | |
1 | /path/to/mypage.inc.php | 9 | {closure} |
2 | /path/to/mypage.inc.php | 2 | func2 |
3 | /path/to/mypage.inc.php | 13 | func1 |
warn(mixed …$arg): Debug
Log a warning
$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');
log()
for examples
getCfg(string $path = null): mixed
Retrieve a configuration value
$debug->log('output', $debug->getCfg('output'));
$debug->log('route', $debug->getCfg('route'));
$debug->log('errorEmailer.emailMin', $debug->getCfg('errorEmailer.emailMin'));
getChannel(string|array $name[, array $config = array()]): Debug
Return a named sub-instance... if channel does not exist, it will be created
Debug
instance$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();
getHeaders(): array
Get and clear debug headers that need to be output
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.
false
.
This will prevent headers from being set automaticallyoutput()
, you can call getHeaders()
$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');
/path/to/mypage.inc.php(25): array (size=1) 0 => array (size=2) 0 => string 'X-ChromeLogger-Data' (length=19) 1 => string 'eyJ2ZXJzaW9uIjoiMy40IiwiY29sdW1ucyI6WyJsb2ciLCJiYWNrdHJhY2UiLCJ0eXBlIl0sInJvd3MiOltbWyJQSFAiLCJHRVQgaHR0cHM6Ly9sb2NhbC5icmFka2VudC5jb20vcGhwL2RlYnVnLzIuMz9jbGVhckNhY2hlIl0sbnVsbCwiZ3JvdXBDb2xsYXBzZWQiXSxbWyJoZWxsbyB3b3JsZCJdLG51bGwsIiJdLFtbXSxudWxsLCJncm91cEVuZCJdXX0=' (length=268)
static meta(mixed …$arg = null): array
"metafy" value/values
meta(array $values): static
meta(string $key[, mixed $value = true]): static
meta(cfg, array $values): static
meta(cfg, string $cfgKey[, mixed $cfgValue = true]): static
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
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() |
$debug->group('group label', $debug->meta('hideIfEmpty'));
$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()): string|null
Return debug log output
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 generally not necessary.
Log will only be output if either of the following conditions are met
// 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();
$config
parametersetCfg(string|array $path[, mixed $value = null[, int $options = 0]]): mixed
Set one or more config values
setCfg('key', 'value')
setCfg('level1.level2', 'value')
setCfg(array('k1'=>'v1', 'k2'=>'v2'))
$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 $caller = null)
A wrapper for errorHandler->setErrorCaller
Example: you deprecate a function and trigger a E_USER_DEPRECATED
error within the function.
Rather than reporting that an error occurred on the file/line of trigger_error()
, you can use
setErrorCaller()
to report the error occurring from the file/line that called the function.
This is is the file/line that will be written to server's error log
This override will apply until cleared, error occurs, or groupEnd()
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);
}
key
or both collect
and output
for the log to be collected & output
$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');
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
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
email
A callable that receives 4 parameters: $to
, $subject
, $body
, & string $additionalHeaders
false
Whether to email a debug log.
Values may be:false
- log not senttrue
) - log sent if there was an error masked by the errorHandler.emailMask
config valuetrue
$_SERVER['SERVER_ADMIN']
Specify where to email logs and error reports
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 achieve 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
null
If a valid filepath, log entries to the file. This will supplement the log that is output via output()
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']
).
key
set to "bosco":
collect
will be set to true
andoutput
will be set to true
collect
and output
will
both be set to false
key takes precedence over collect
and output
array(
'cookies' => true,
'headers' => true, // request headers
'phpInfo' => true, // PHP_VERSION, ini file locations, memoryLimit, etc
'post' => true, // $_POST (or request body), & $_FILES
'serverVals' => true, // $_SERVER values specified by logServerKeys
)
Specify "environment" information to automatically log.
Also accepts true
(all), or false
(none), or string[]
.
$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'));
array("DOCUMENT_ROOT","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 applicableREQUEST_METHOD
will be included if REQUEST_METHOD != 'GET'
null
A callable to be invoked when debug instance is created.
If setting onBootstrap
on an existing instance, it will be called immediately
null
\bdk\PubSub\Event $event
.\bdk\Debug\LogEntry
object (extends \bdk\PubSub\Event)null
\bdk\PubSub\Event $event
.(string) $outputAs
to \bdk\PubSub\Event
false
Should output()
actually output the log?
It is not necessary to explicitly set to true
if using the key config setting
These options deal with how the log is output
null
null
),
output will be determined based on request / response
<script></script>
containing console.xxx calls\bdk\Debug\PluginInterface
chromeLogger
If outputAs is null
, this value will be used for http requests that are ajax or non-html response
true
Should PHPDebugConsole output headers (ie, ChromeLogger, FirePHP, & ServerLog headers) on output?
false
Convert "\n" to "<br />\n" in strings?
white-space: pre
(as base css does)Supplemental CSS to output
./css/Debug.css
Filepath to base CSS.
./js/Debug.jquery.min.js
Filepath to javascript to include.
//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js
Only loaded if window.jQuery
is undefined
true
Output filepathCss contents with the log?
true
Output filepathScript contents with the log?
These options deal specifically with debugging objects
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)")
visibility
How to sort properties and methods.
Accepts "visibility", "name", or false|null
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.
__debugInfo
value differs from regular value, the property will be listed with icon .__debugInfo
, it will be listed with "debug" visibilitytrue
Whether to collect object constants
true
Whether to output object's constants
true
Whether to collect object methods, return types, parameter information, etc
true
Whether to output object's methods
true
Whether PHPDebugConsole assumes all instances of a given class will have the same methods.
The need to disable this is extremely rare
true
Whether to output method's long phpDoc description
capture = false
at time of error)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
15
Number of minutes that must elapse before resending an email notice for unique errors
__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
callable
A callable that returns throttle data. If not specified, throttle data is read from emailThrottleFile.
callable
A callable that receives throttle data as a single param. If not specified, throttle data is written to emailThrottleFile.
true
Whether to send an email summary of throttled errors on trash-collection
E_ERROR | E_WARNING | E_USER_ERROR | E_USER_NOTICE
Specify which types of errors should include a backtrace
true
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).
log
E_USER_ERROR
and E_RECOVERABLE_ERROR
from terminate to continue"normal"
valueE_USER_ERROR
and E_RECOVERABLE_ERROR
.
This config option gives you control
allowed values:
"continue"
"log"
$error['continueToNormal'] == true
"normal"
null|false
$error['continuetoNormal'].
true
: log the errorfalse
: continue without loggingnull
A callable to be invoked when error occurs.
\bdk\PubSub\Event $error
\bdk\PubSub\Event
object\bdk\ErrorHandler\Error
object (extends \bdk\PubSub\Event)Version 2.0 introduces events (aka publish/subscribe) that allow allow you to extend PHPDebugConsole and/or create plugins.
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 invoke the handler immediately.published when config is updated
$event->getSubject()
to get the debug object$event['config']
contains the changed config valuespublished when a debug method is called
true
$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$event->stopPropagation()
to prevent the log-entry from being loggedCreate 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
stopPropagation()
will prevent this
$event['appendLog']
instead of $event->stopPropagation()
to control whether to logpublished 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
stopPropagation()
will prevent this
published before object is inspected
This event gives access to the object abstraction before the heavy lifting takes place
Subscribers to this event may:$event->getSubject()
to get the object being inspected
stopPropagation()
will prevent this
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
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).
$event->getSubject()
to get debug instance$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)published when a php error occurs
$event->getValues()
to get all error info$event->stopPropagation()
to prevent continuation to previous error handlerPublished 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
ChromeLogger outputs your log via http headers. The log is viewed in your browser's console via extension/addon
ob_start()
is one way to hold script output until the end of the script.
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.
ob_start()
is one way to hold script output until the end of the script.
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.
If you're using a library that uses psr/log, or monolog/monolog, getting up and runniing with PHPDebugConsole couldn't be easier.
logger method | maps to |
---|---|
$logger->emergency() |
$debug->error() |
$logger->alert() |
$debug->alert() |
$logger->critical() |
$debug->error() |
$logger->error() |
$debug->error() |
$logger->warning() |
$debug->warn() |
$logger->notice() |
$debug->warn() |
$logger->info() |
$debug->info() |
$logger->debug() |
$debug->log() |
$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');
$monolog = new \Monolog\Logger('PHPDebugConsole');
$monolog->pushHandler(new \Monolog\Handler\PsrHandler($debug->logger));
$monolog->info('yup, it works');
addClass($className, $filepath)
& addPsr4($namespace, $dir)
E_STRICT
)@deprecated
, @since
, & version
tags now parsed into version & desc valuesalert()
- now accepts multiple arguments (like log, info, error, & warn)trace()
- new limit argument. Arguments may be passed in any orderTYPE_IDENTIFIER
(for constants, classNames, properties, methodsTYPE_CONST
& TYPE_STRING_CLASSNAME
ArrayAccess
)['attributes', 'extends', 'implements', 'constants', 'cases', 'properties', 'methods', 'phpDoc']
Debug::varDump()
not escaping special charsUtility/Php::getIniFiles()
not properly handling empty return from php_ini_scanned_files()
ErrorHandler::handleException()
- check headers_sent()
before calling http_response_code(500)
$_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 paramHttpMessage\Uri::fromGlobals()
is now a public static methodvarDump
static method for in-place var_dump
-like debugging\bdk\Debug::log('this is new')
and \bdk\Debug::_log('still works')
UriUtils::parseUrl()
#[\SensitiveParameter]
supportgetChannel()
true
) Whether headers should be output (ie with chromeLogger and firePHP) this provides flexibility with frameworks, PSR7 responseInterface
, etcthrottleData
in ErrorEmailer.php__debugInfo
are now output with ability to show/hide (like private/protected)__debugInfo()
method__debugInfo()
is no longer called if collectPropertyValues is falseassert()
- support for styling/substitutionsgroupEnd()
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.html_errors
and docref_root
php settings. Don't double htmlspecialchars() error message$path
parameter removed from dump()
methodclear()
method\bdk\Debug\Utilities
methods beefed up & now more useful outside debugger: arrayPathGet, arrayMergeDeep, & getCallerInfosetCfg('string', newValue)
not properly returning previous value -> collect is always on. Bug introduced in v2.1. Unit-test added.log()
log()
alert()
now publishes debug.outputLogEntry when being output\bdk\Debug\Utilities::buildAttribString()
- now with more utility\bdk\Debug::_setConfig()
, \bdk\Debug::_log('collect is false, so this is pointless')
, etc. Because why notcount()
title
attribute for htmlgroupSummary()
calls can now be nested & other groupSummary improvementstable()
Traversable
object as param. Array-o-traversable was already a thing, but top-level Traversable had been overlooked__toString
value if applicable$debug->addPlugin()
)
php://input
and content-type if $_POST
is emptyE_USER_ERROR
behaviorErrorHandler
and ErrorEmailer
moved outside of bdk\Debug namespace / have no dependenciesOutputInterface
alert()
, table()
, & groupSummary()
cfg.output == true
\func_get_args()
)\bdk\Debug::_setCfg(array('collect'=>true, 'output'=>true));
array(object, 'string')
(callable)\bdk\Debug
(was \bdk\Debug\Debug
)
get()
& set()
methods renamed to getCfg()
& setCfg()
respectfully.
\bdk\Debug::_log('I was logged statically');
{@inheritdoc}
@method
& @property
tags incoporated into object's property & method list@link
& @see
(when url)__toString
value is now limited to 100 chars
& ©
) will still appear as html entities
table()
alert()
: create an alertgroupSummary()
: group entries at top of outputmeta()
: create a meta value(s) argumenttrace()
: equiv to console.trace()
getIncludedFiles()
- get_included_files()
plus logical sortinggroup()
and groupCollapsed()
array(Object, 'string')
now interpreted & displayed as a callableFirePHP.class.php
(aka firephp core library)\bdk\Debug
(options were passed to FirePHP.class.php)
\bdk\PubSub\Event
object (onError received an array, onOutput received the debug instance)
onLog
- "published" before data appended to logstopPropagation()
on the passed event object to prevent logging
HTTP_REFERER
now included in error emailget()
and set()
now only have access to configurationdataGet()
and dataSet()
methods for directly interacting with the log datatimeEnd()
and timeGet()
accept a template. default: "%label: %time"cfg['collect']
table()
methodcall_user_func
was in the stack traceemailThrottledSummary
: new option to disable email summary of throttled errors
emailMin
minutes.emailMin
minutes ago (and which did not trigger an email notice), a summary of these errors will be emailedobjectExclude
option - specify classNames to exclude from inspecting if found nested in array or object propertiesobjectSort
option - sort object's properties, methods, & constants by 'name', 'visibility', or unsorted__debugInfo
method now used if defineduseDebugInfo
, collectConstants
, outputConstants
emailfunc
(default value = "mail")to
, subject
, and body
. Email's generated by the debugger are passed to this function.
collectMethods
(default value = true
)outputMethods
(default value = true
)outputAs
option: "script"<script>
with console
calls
output()
is no longer necessaryboolean
to array
array $error
- an array containing all sorts of useful error details.$error['category']
will be "fatal"
get('lastError')
boolean $isFatal
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.errorMask
option from ErrorHandler to DebugDocumentation coming soon, but a few core ErrorHandler methods include:
array $error
namespace bdk\Debug;
cfg
and data
properties are now protected
getInstance
method - which is the preferred way to instantiate the class:
$debug = \bdk\Debug::getInstance();
setCfg()
. Use set()
(which semantically matches "get()")./FirePHP/FirePHP.class.php
to ./FirePHP.class.php