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 |
Note that v3.3 has not yet been released.
We are specifying the most recent release version (3.2) below.
Install via Composer as bdk/debug
{
"require": {
"bdk/debug": "^3.2"
}
}
—or—
composer require bdk/debug:^3.2
<?php
require __DIR__ . '/vendor/autoload.php';
$debug = new \bdk\Debug(array(
'collect' => true,
'output' => true,
));
$debug->log('hello world');
SERVER_ADMIN
(configurable / disabled by default)\bdk\Debug::_log('I was logged statically');
$_SESSION
, & files included during request. If using a framework extension/bundle, more information may be logged
E_ALL | E_STRICT
expose_php
is disabled, whether common extensions, curl & mbstring enabled, whether xdebug is enabledPHPDebugConsole dumps just about every piece of info you would need to know about an object
Did value come from object's debugInfo()
method?
PHP Attributes are inspected for Class, Constants, Properties, Methods, Method Params
__get
method__call
method$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');
Note:
As of v3.1, Any method added via plugin (every method of interest) may be called statically without the underscore prefix.
example: \bdk\Debug::log('I was logged statically');
alert(mixed …$args): static
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/buttonTwo method signatures:
alert(...$args)
alert(string $message, string $level = 'error', bool $dismissible = false)
Can use styling & substitutions.
If using substitutions or passing arbitrary arguments, 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
htmlspecialchar()'d
by defaultmeta('sanitizeFirst', false)
to allow htmlgroup(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); // use _ prefix if using < v3.1
\bdk\Debug::log('Analyizing the data...'); // use _ prefix if using < v3.1
$return = false;
\bdk\Debug::groupEnd($return); // use _ prefix if using < v3.1
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); // use _ prefix if using < v3.1
\bdk\Debug::log('Analyizing the data...'); // use _ prefix if using < v3.1
$return = false;
\bdk\Debug::groupEnd($return); // use _ prefix if using < v3.1
return $return;
}
groupEnd(mixed $value = bdk\Debug\Abstraction\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); // use _ prefix if using < v3.1
\bdk\Debug::log('Analyizing the data...'); // use _ prefix if using < v3.1
$return = false;
\bdk\Debug::groupEnd($return); // use _ prefix if using < v3.1
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
htmlspecialchar()'d
by defaultmeta('sanitizeFirst', false)
to allow htmllog(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);
htmlspecialchar()'d
by defaultmeta('sanitizeFirst', false)
to allow htmlprofile(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 = null]): 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 $log = true[, bool|auto $return = auto]]): bdk\Debug|float|false
Behaves like a stopwatch.. logs and (optionally) returns running time
4
) how many decimal placestimeEnd('label')
will return the same value until unpaused with time('label')
$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 $log = true[, bool|auto $return = auto]]): bdk\Debug|float|false
Log/get the running time without stopping/pausing the timer
false
if specified label does not exist4
) how many decimal placesqueryDb('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', $debug->meta('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[, int $limit = 0]]): 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(); // use _ prefix if using < v3.1
};
$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 |
varDump(mixed …$arg)
Dump values to output
Similar to php's var_dump()
. Dump values immediately
echo '<p>Addicted to spuds</p>';
$result = $oven->bake('potato');
\bdk\Debug::varDump('result', $result);
echo '<p>can\'t get enough</p>';
Addicted to spuds
"result" = array( [food] => "potato" [temperature] => 400 [buttery] => true )
can't get enough
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
htmlspecialchar()'d
by defaultmeta('sanitizeFirst', false)
to allow htmladdPlugin(AssetProviderInterface|SubscriberInterface $plugin[, string $name = null]): Debug
Extend debug with a plugin
getCfg(string $path = null): mixed
Retrieve a configuration value
$debug->log('output', $debug->getCfg('output'));
$debug->log('route', $debug->getCfg('route'));
$debug->log('errorHandler.emailer.emailMin', $debug->getCfg('errorHandler.emailer.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\bdk\Debug::EVENT_LOG
, \bdk\Debug::EVENT_OBJ_ABSTRACT_START
, and \bdk\Debug::EVENT_OBJ_ABSTRACT_END
events "bubble" up ancestor channels.
$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 \bdk\Debug::EVENT_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(\bdk\Debug::EVENT_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');
array( [0] => array( [0] => "X-ChromeLogger-Data" [1] => "eyJ2ZXJzaW9uIjoiMy4zIiwiY29sdW1ucyI6WyJsb2ciLCJiYWNrdHJhY2UiLCJ0eXBlIl0sInJvd3MiOltbWyJQSFAiLCJHRVQgaHR0cHM6Ly9sb2NhbC5icmFka2VudC5jb20vcGhwL2RlYnVnLzMuMz9j[112 more bytes (not logged)]" ) )
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
parameterremovePlugin(string|SubscriberInterface $plugin): Debug
Remove plugin
setCfg(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()-> // use _ prefix if using < v3.1setErrorCaller()
trigger_error('trustyOldFunction\'s days are numbered. Use superNewFunction instead.', E_USER_DEPRECATED);
}
writeToResponse(ResponseInterface|HttpFoundationResponse $response): ResponseInterface|HttpFoundationResponse
Appends debug output (if applicable) and/or adds headers (if applicable)
You should call this at the end of the request/response cycle in your PSR-7 project, e.g. immediately before emitting the Response.
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');
array()
Provide configuration for yet-to-be-created channels
example:
array(
'channelName' => array(
'channelIcon' => 'fa fa-bolt',
)
)
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 senterrorHandler.emailMask
config valuetrue
(or 'always') - log always sent (if not being output)See email route for more information
\bdk\Debug\Utility\Utility\SerializeLog::unserialize()
\bdk\Debug::setData($unserialized)
true
true
is now synonymous with "always" (was "onError")$_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
250000
Maximum size of all headers combined. (Chrome has a limit of 256KB)
null
If defined, the maximum size any individual header should be.
Primarily for ChromeLogger… behind a proxy/load-balancer.
If you run into an issue, try setting this value to "16K", "8K", "8000", etc
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(
'errorReporting' => true, // notice if not `E_ALL | E_STRICT`
'files' => true, // files included during request
'gitInfo' => true, // git branch if applicable
'phpInfo' => true, // PHP_VERSION, ini file locations, memoryLimit, etc
'serverVals' => true, // $_SERVER values specified by logServerKeys
'session' => true, // session data
)
Specify "environment" information to automatically log.
Also accepts true
(all), or false
(none), 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(
'cookies' => true,
'files' => true, // $_FILES
'headers' => true, // request headers
'post' => true, // $_POST (or request body)
)
Specify request information to automatically log.
Also accepts true
(all), or false
(none).
$debug = new \bdk\Debug(array(
'collect' => true,
'output' => true,
'logRequestInfo' => true, // this is the default (all other examples use `false`),
'logResponse' => true, // this is the default (other other examples use `false`),
));
value | |
---|---|
Content-Type | text/html |
Cookie | SESSIONID=5umr2d3e392f6idhvpadiqs7r0 |
auto
Whether to begin buffering output & potentialy log response
auto
SoapAction
header, or have a Accepts
header that does not contain "html"true
false
If output is being buffered, we will log the output upon shutdown if response Content-Type is json or xml.
See also writeToResponse()
1 MB
Set a size limit to logging response
If size is exceeded, response will not be output
integer or string
0 / null : No Limit
true
Log script duration and memory usage.
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'
0
Controls how many nested levels of array elements and object properties are traversed.
A value <= 0 does not enforce a maximum depth
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\Debug\LogEntry $logEntry
.\bdk\Debug::EVENT_LOG
event\bdk\Debug\LogEntry
object (extends \bdk\PubSub\Event)null
\bdk\PubSub\Event $event
.
Event object contains request
and response
objects
\bdk\Debug::EVENT_MIDDLEWARE
event.null
\bdk\PubSub\Event $event
.\bdk\Debug::EVENT_OUTPUT
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
array("password")
A list of keys that should be redacted when redact meta option is passed.
Keys will also be found and redacted in url-encoded strings, xml, & json
The string (or portion thereof) that needs redacted will be passed to the callable defined by redactReplace
$debug->log('response', $xml, $debug->meta('redact'));
Perform redaction on an array
$debug->log('api params', $params, $debug->meta('redact'));
Redaction is performed on out-of-the-box logging of input/$_POST
, $_COOKIE
, request headers, $_SERVER
values, & response
callable
A callable that receives the string being redacted and the key
Default callable returns "█████████"
See also redactKeys
array()
\bdk\Container\ServiceProviderInterface
, array
, or callable
that receives \bdk\Container
as param.
Used to specify dependencies
null
If logging session data (see logEnvInfo), optionally specify session name
If not specified, we will try "PHPSESSID" (php's default, but not recommended), "SESSIONID", "SESSION_ID", "SESSID", and "SESS_ID"
null
A valid filepath, stream-url, or resource, to write the log. This will supplement the log that is output via output()
array(
'base64' => 154, // only 1st 154 chars of base-64 string will be shown
'binary' => array(
128 => 0, // if over 128 bytes don't capture / store
),
'other' => 8192,
)
Controls the maximum string length (in bytes) that is collected/shown for string values
specifying an int
(vs array) will set the "other" value
-1
= no maximum
array(
'contentType' => 256, // try to determine content-type of binary string
'encoded' => 16, // test if base64, json, or serialized (-1 = don't check)
)
Specify the minimum length of a string before we inspect it to determine the content-type or check if json/base64/serialized
These options deal with how the log is output
true
Should PHPDebugConsole output headers (ie, ChromeLogger, FirePHP, & ServerLog headers) on output?
auto
"auto"
),
output "route" will be determined based on request / response
route
specifies the "primary" route. Additional routes may be added with addPlugin().<script></script>
containing console.xxx calls\bdk\Debug\RouteInterface
chromeLogger
If route is "auto"
, this value will be used for http requests that are ajax or non-html response
Supplemental CSS to output
true
Place output in dockable "drawer"
./css/Debug.css
Filepath to base CSS.
./js/Debug.jquery.min.js
Filepath to javascript to include.
//ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js
Only loaded if window.jQuery
is undefined
true
Output filepathCss contents with the log?
true
Output filepathScript contents with the log?
true
Display filter sidebar?
These options deal specifically with debugging objects
true
Whether to collect enum cases
true
Whether to output enum cases
true
Whether to collect attributes attached to enum cases
true
Whether to output enum case attributes
true
Whether to collect object constants
true
Whether to output objects constants
true
Whether to collect attributes attached to class constants
true
Whether to output constant attributes
array("ArrayAccess","BackedEnum","Countable","Iterator","IteratorAggregate","UnitEnum")
Methods implementing these interfaces will be initially hidden
true
Whether to collect attributes attached to class
true
Whether to output class attributes
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)"
array("attributes","extends","implements","constants","cases","properties","methods","phpDoc")
Specify The order to output object information
inheritance visibility name
How to sort properties and methods.
true
Whether to collect PhpDoc description & summary (for obj, constants, properties, methods, & method params)
true
Whether to output PhpDoc description & summary (for obj, constants, properties, methods, & method params)
true
Whether to output the __toString()
return value
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 methods, return types, parameter information, etc
true
Whether to output object's methods
true
Whether to collect attributes attached to methods
true
Whether to output method attributes
true
Whether to output method's long phpDoc description
true
Whether to collect static variables within methods
true
Whether to output method static variables
true
Whether to collect attributes attached to method parameters
true
Whether to output method parameters attributes
true
Whether to collect attributes attached to properties
true
Whether to output attributes attached to properties
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
60
Number of minutes that must elapse before resending an email notice for unique errors
60
(was 15
)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
false
Send error notifications via email
__DIR__ . '/error_emails.json'
A file used to maintain details of recent errors.
Warning: emailThrottleFile
should be set to a path outside the document root or .htaccess should be configured to prevent access / return a 404
true
false
Whether to log the error to the error_log as "normal" when the debugger is capturing errors
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\ErrorHandler\Error $error
\bdk\PubSub\Event
object\bdk\ErrorHandler\Error
object (extends \bdk\PubSub\Event)\bdk\Debug::EVENT_BOOTSTRAP
published when debug is instantiated
Primarily used internally. This event is published after the debug instance is created. This event can be subscribed to by passing the onBootstrap config option to the debug constructor. If the debug instance has already been instantiated, setting onBootstrap via setCfg will invoke the handler immediately.\bdk\Debug::EVENT_CONFIG
published when config is updated
$event->getSubject()
to get the debug object$event->getValues()
to get changed config values$event->getValues()
\bdk\Debug::EVENT_CUSTOM_METHOD
published when a non-core method is called
Set$event['handled'] = true
if "handled".
If not "handled" the log-entry will trigger \bdk\Debug::EVENT_LOG
event with meta value 'isCustomMethod' = true
\bdk\Debug::EVENT_DUMP_CUSTOM
published when dumping an unknown "abstraction" object;
\bdk\Debug::EVENT_LOG
published 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['appendLog'] = false
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 log\bdk\Debug::EVENT_MIDDLEWARE
published before middleware writes to response
This event only applies if using PHPDebugConsole's middleware
$event->getSubject()
to get debug instance$event['request']
contains the ServerRequestInterface$event['response']
contains the ResponseInterface\bdk\Debug::EVENT_OBJ_ABSTRACT_END
published after object is inspected
This event gives access to the object abstraction after the heavy lifting took place
subscribers to this event have complete control to modify the abstraction values:
Call$event->getSubject()
to get the inspected object
stopPropagation()
will prevent this
\bdk\Debug::EVENT_OBJ_ABSTRACT_START
published before object is inspected
This event gives access to the object abstraction before the heavy lifting takes place
Subscribers to this event may:\bdk\Debug::EVENT_OBJ_ABSTRACT_START
subscriber to set stringified to a human readable format
$event->getSubject()
to get the object being inspected
stopPropagation()
will prevent this
\bdk\Debug::EVENT_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
\bdk\Debug::EVENT_OUTPUT_LOG_ENTRY
For each enabled output plugin, published as each individual log entry is output
Use this event to customize how a particular method is displayed / or to handle custom methods (unhandled methods will be handled the same as a plain 'ol log()
call).
\bdk\Debug::EVENT_LOG
is published when you call a debug method.\bdk\Debug::EVENT_OUTPUT_LOG_ENTRY
is published when that log entry is output$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 Route/Html object)$event['route']
value\bdk\Debug::EVENT_PLUGIN_INIT
Published exclusively to the plugin being added
Use this event to do any initialization a plugin may require.
$event->getSubject()
to get debug instance\bdk\Debug::EVENT_PRETTIFY
Prettify php://input
, Guzzle message bodies, and curl response body
We will prettify html, json, & xml. Use this event to customize, or to handle other content-types
$event->stopPropagation()
if handling$event['contentType']
contains the content/mime type$event['value']
contains the string to prettify\bdk\Debug::EVENT_STREAM_WRAP
Modify PHP code as it's loaded
If enableProfiling is enabled, \bdk\Debug::EVENT_STREAM_WRAP
will be published
when a file gets required/included.
Internally we use this event to inject declare(ticks=1);
- necessary for our profile method.
$event->getSubject()
returns the php://memory resource that will contain the modified PHP code$event['content']
contains file contents$event['filepath']
contains the filepath being required\bdk\ErrorHandler::EVENT_ERROR
published when a php error occurs
$event->getValues()
to get all error info$event->stopPropagation()
to prevent continuation to previous error handler\bdk\PubSub\Manager::EVENT_PHP_SHUTDOWN
Published when script execution finishes or exit()
is called
Provided via our underlying event manager
This event is essentially a helper/wrapper for register_shutdown_function
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.
As a workaround you can set the headerMaxPer option to limit the output
Send error notification to Discord webhook
E_ERROR | E_PARSE | E_COMPILE_ERROR | E_WARNING | E_USER_ERROR
) What errors should plugin handlenull
) Callable that will receive the curl client60
) how many minutes should elapse before resending the same errorDISCORD_WEBHOOK_URL
env var) Discord webhook url// enable via plugins config array
$debug = new \bdk\Debug(array(
'plugins' => array(
'discord' => array(
'class' => 'bdk\\Debug\\Route\\Discord',
'webhookUrl' => 'https://discord.com/api/webhooks/123456789/abcdefg-hijklmnop-qrstuv-wx_yz',
),
),
));
// OR add to debug via addPlugins
$discordPlugin = $debug->getRoute('discord')->setCfg(array(
'webhookUrl' => 'https://discord.com/api/webhooks/123456789/abcdefg-hijklmnop-qrstuv-wx_yz',
));
$debug->addPlugin($discordPlugin);
Email the log!
It may be useful to email the log if an error occured…
true
true
\bdk\Debug\Utility\SerializeLog::unserialize()
\bdk\Debug\Utility\SerializeLog::import($unserialized)
true
for there to be any log entries to email!
ob_start()
is one way to hold script output until the end of the script.
The default route
Log is output as <script>
tag with console.xxx calls
<script type="text/javascript">
console.log("hello world");
console.log("etc.");
</script>
$debug = new \bdk\Debug(array(
'key' => 'example_password',
'route' => 'script',
));
$debug->alert('This is the script route example');
$debug->info('this is a script test');
$debug->table(array(
array('city' => 'Atlanta', 'state'=>'GA', 'population'=>472522,),
array('city' => 'Buffalo', 'state'=>'NY', 'population'=>256902,),
array('city' => 'Chicago', 'state'=>'IL', 'population'=>2704958,),
array('city' => 'Denver', 'state'=>'CO', 'population'=>693060,),
array('city' => 'Seattle', 'state'=>'WA', 'population'=>704352,),
array('city' => 'Tulsa', 'state'=>'OK', 'population'=>403090,),
), 'Table');
echo 'This example output can be found in your browser console!';
ServerLog writes your log to a temporary JSON file. A url to this file is output via a header. A browser extension/addon retrieves the log and displays it in your browser's console
There are a handful of config options for ServerLog. Here are the two important ones
DOCUMENT_ROOT . '/log'
'/log/{filename}'
$debug = new \bdk\Debug(array(
'routeServerLog' => array(
'logDir' => '/tmp/',
'urlTemplate' => '/serverLog/{filename}',
),
'route' => 'serverLog',
// 'collect' and / or 'key' must also be configured
));
X-ServerLog-Location
is being output. (Use your browser's developer console / network tab to inspect the request/response.)Send error notification to Slack
SLACK_CHANNEL
env var) If using Slack api, specify channel to post toE_ERROR | E_PARSE | E_COMPILE_ERROR | E_WARNING | E_USER_ERROR
) What errors should plugin handlenull
) Callable that will receive the curl client60
) how many minutes should elapse before resending the same errorSLACK_TOKENL
env var) If using Slack api, specify tokenSLACK_WEBHOOK_URL
env var) Slack webhook url// enable via plugins config array
$debug = new \bdk\Debug(array(
'plugins' => array(
'slack' => array(
'class' => 'bdk\\Debug\\Route\\Slack',
'webhookUrl' => 'https://hooks.slack.com/services/QWERTY/DVORAK/PCMCIA',
),
),
));
// OR add to debug via addPlugins
$slackPlugin = $debug->getRoute('slack')->setCfg(array(
'webhookUrl' => 'https://hooks.slack.com/services/QWERTY/DVORAK/PCMCIA',
));
$debug->addPlugin($slackPlugin);
Stream to STDERR
or file pointer
This is the default route for command line scripts.
STDERR
// begin outputting log entries to specified filepath
// primary route is unaffected / this will supplement
$debug->setCfg('stream', '/some/filepath.txt');
// only output log to filepath
// 'output' will need to be true or 'key' set & matching
$debug->setCfg(array(
'route' => 'stream',
'stream' => '/some/filepath.txt',
));
Send error notification to MS Teams
E_ERROR | E_PARSE | E_COMPILE_ERROR | E_WARNING | E_USER_ERROR
) What errors should plugin handlenull
) Callable that will receive the curl client60
) how many minutes should elapse before resending the same errorTEAMS_WEBHOOK_URL
env var) Teams webhook url// enable via plugins config array
$debug = new \bdk\Debug(array(
'plugins' => array(
'teams' => array(
'class' => 'bdk\\Debug\\Route\\Teams',
'webhookUrl' => 'https://wxyz8.webhook.office.com/webhookb2/supercalifragilisticexpialidocious/IncomingWebhook/blablah/blah-blah-blah',
),
),
));
// OR add to debug via addPlugins
$teamsPlugin = $debug->getRoute('teams')->setCfg(array(
'webhookUrl' => 'https://wxyz8.webhook.office.com/webhookb2/supercalifragilisticexpialidocious/IncomingWebhook/blablah/blah-blah-blah',
));
$debug->addPlugin($teamsPlugin);
Plain / boring text output
$debug = new \bdk\Debug(array(
'collect' => true,
'output' => true,
'route' => 'script',
));
$debug->alert('this is an alert!');
$debug->info('you have 30 minutes to move your car');
$debug->warn('your car has been impounded');
$debug->error('your car has been crushed into a cube');
$debug->table(array(
array('city' => 'Denver', 'state'=>'CO', 'population'=>693060,),
array('city' => 'Seattle', 'state'=>'WA', 'population'=>704352,),
array('city' => 'Tulsa', 'state'=>'OK', 'population'=>403090,),
), 'Table');
》[Alert ⦻ error] this is an alert!《 ℹ you have 30 minutes to move your car ⚠ your car has been impounded ⦻ your car has been crushed into a cube Table = array( [0] => array( [city] => "Denver" [state] => "CO" [population] => 693060 ) [1] => array( [city] => "Seattle" [state] => "WA" [population] => 704352 ) [2] => array( [city] => "Tulsa" [state] => "OK" [population] => 403090 ) )
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.
Use PHPDebugConsole with the frameworks and tools you already use.
How-To Guides and plugins for common frameworks
'PHPDebugConsole' => array(
'key' => 'dingus',
),
$this->addPlugin(new \bdk\Debug\Framework\Cake4());
.env
file and add PHPDEBUGCONSOLE_KEY = somePassword
run php artisan vendor:publish --tag=config
You should now have a config/phpDebugConsole.php config file
This file can be used to set all PHPDebugConsole config options including some Laravel-specific options
laravel
is a list of laravel-specific information that you would like to collect / outputoptions
contains collector-specific options for the aboveAccess your Laravel site with ?debug=somePassword (where "somePassword" is the password/key set in config/phpDebugConsole.php
… likely the PHPDEBUGCONSOLE_KEY value)
/*
create slim v2 app
*/
$app = new \Slim\Slim(array(
'debug' => false,
));
/*
Add logging via PHPDebugConsole
*/
$app->hook('slim.before', function () use ($app) {
$app->log->setWriter(new \bdk\Debug\Framework\Slim2());
});
/*
Add Routes & Run
*/
$app->get('/hello/:name', function ($name) {
echo 'Slim, '.$name.'<br />';
});
$app->run();
Our Yii 1.1 component will
Yii::app()->db
with \bdk\Debug\Collector\Pdo (log PDO queries)Yii::app()->debug
Require bdk/debug via composer (how)
Edit your Yii config
array(
// add to components
'components' => array (
'phpDebugConsole' => array (
'class' => '\\bdk\\Debug\\Framework\\Yii1_1\\Component',
// debug config values
// best to replace 'collect' & 'output' with 'key'
'collect' => true,
'output' => true,
// optional yii specific options
'yii' => array(
'ignoredErrors' => true, // yii 1.1 framework throws a lot of deprecation and notices
// we "ignore" these errors
// this setting will show a summary of these ignored errors
'log' => true, // whether to set up a yii log route and capture Yii log messsaegs
'pdo' => true, // capture database queries
'session' => true, // log session info / data
'user' => true, // log current user info
)
),
),
// add to preload
'preload' => array('phpDebugConsole'),
// may need to add an alias
'aliases' => array(
'bdk.Debug.Framework' => 'path/to/Debug/Framework/Yii1_1',
),
);
You may also want to define YII_DEBUG
when bootstraping your app
define('YII_DEBUG', true);
Require bdk/debug via composer (how)
Edit your Yii config
/*
Add to bootstrao and modules arrays
Make sure that 'phpDebugConsole' comes first in the boostrap array
to ensure we intercept the instantiation of the database connection
*/
$config['bootstrap'][] = 'phpDebugConsole';
$config['modules']['phpDebugConsole'] = [
'class' => 'bdk\Debug\Framework\Yii2\Module',
// debug config values
// best to replace 'collect' & 'output' with 'key'
'collect' => true,
'output' => true,
// optional yii specific options
'yii' => [
'events' => true, // summary of all dispatched events
'log' => true, // whether to set up a yii log target and capture Yii log messsaegs
'pdo' => true, // capture database queries
'session' => true, // log session info / data
'user' => true, // log current user info
],
];
PHPDebugConsole includes Adaptors / Decorators / Helpers / Proxies / Wrappers for common "components"
Doctrine Database Abstraction Layer
Log Doctrine via Doctrine\DBAL\Logging\SQLLogger
interface.
(Deprecated as of Doctrine 3.2)
/*
Get the Doctrine connection obj
*/
$conn = \Doctrine\DBAL\DriverManager::getConnection(array(
'url' => 'mysql://user:secret@localhost/mydb',
));
/*
Instantiate PHPDebugConsole's Doctrine Logger and set Doctrine's logger
*/
$logger = new \bdk\Debug\Collector\DoctrineLogger($conn);
$conn->getConfiguration()->setSQLLogger($logger);
$statement = $conn->prepare('SELECT *
FROM `users`
WHERE `username` = :username');
$username = 'james.bond';
$statement->bindParam(':username', $username, PDO::PARAM_STR);
$statement->execute();
value | type | |
---|---|---|
:username | james.bond | Doctrine\DBAL\ParameterType::STRING |
Doctrine Database Abstraction Layer
Log Doctrine via Doctrine\DBAL\Driver\Middleware
interface.
(Doctrine 3.2+)
/*
Get the Doctrine connection obj with our middleware
Middleware must be added on connection instantiation
*/
$dsnParser = new \Doctrine\DBAL\Tools\DsnParser();
$params = $dsnParser->parse('mysql://user:secret@localhost/mydb');
$config = (new \Doctrine\DBAL\Configuration())->setMiddlewares([
new \bdk\Debug\Collector\DoctrineMiddleware(),
]);
$conn = \Doctrine\DBAL\DriverManager::getConnection($params, $config);
$statement = $conn->prepare('SELECT *
FROM `users`
WHERE `username` = :username');
$username = 'james.bond';
$statement->bindValue(':username', $username, \Doctrine\DBAL\ParameterType::STRING);
$statement->executeQuery();
value | type | |
---|---|---|
:username | james.bond | Doctrine\DBAL\ParameterType::STRING |
$stack = \GuzzleHttp\HandlerStack::create();
$stack->push(
new \bdk\Debug\Collector\GuzzleMiddleware(array(
'inclRequestBody' => true, // default is false
'inclResponseBody' => true, // default is false
))
);
$client = new \GuzzleHttp\Client(array(
'cookies' => true,
'handler' => $stack,
));
$response = $client->request('GET', 'http://example.com/');
$guzzleClient->getConfig('handler')->push(
new \bdk\Debug\Collector\GuzzleMiddleware(array(
'inclRequestBody' => true, // default is false
'inclResponseBody' => true, // default is false
))
);
$response = $guzzleClient->request('GET', 'http://example.com/');
There are two ways to use PHPDebugConsole as a monolog "handler"
PHPDebugConsole provides a monolog handler.
This handler will pass along the monolog channel.
$monolog = new \Monolog\Logger('PHPDebugConsole');
$monolog->pushHandler(new \bdk\Debug\Collector\MonologHandler());
$monolog->info('yup, it works');
Use Monolog's PSR-3 handler with PHPDebugConsole's PSR-3 logger
$monolog = new \Monolog\Logger('PHPDebugConsole');
$monolog->pushHandler(new \Monolog\Handler\PsrHandler($debug->logger));
$monolog->info('yup, it works');
/*
Instantiate and use PHPDebugConsole's MySqli client (in lieu of PHP's mysqli client)
*/
$mysqli = new \bdk\Debug\Collector\MySqli('localhost', 'my_user', 'my_pass', 'my_db');
$stmt = $mysqli->prepare("INSERT INTO `some_table` (`int`, `float`, `text`) VALUES (?, ?, ?)");
$stmt->bind_param('idds', $int, $decimal, $float, $text);
$int = 42;
$float = 3.14;
$text = 'sweet';
// execute prepared statement
$stmt->execute();
/*
Use the PHPDebugConsole OAuth class (extends OAuth)
All requests will be logged
*/
$oauthClient = new \bdk\Debug\Collector\OAuth($consumerKey, $consumerSecret);
$pdoBase = new \PDO('sqlite::memory:');
$pdo = new \bdk\Debug\Collector\Pdo($pdoBase);
$stmt = $pdo->prepare('SELECT *
FROM `bob`
WHERE e < :datetime');
$datetime = date('Y-m-d H:i:s');
$stmt->bindParam(':datetime', $datetime, PDO::PARAM_STR);
$stmt->execute();
value | type | |
---|---|---|
:datetime | 2024-10-28 20:11:22 | PDO::PARAM_STR |
$curl = new \bdk\Debug\Collector\PhpCurlClass(array(
'inclResponseBody' => true,
));
$curl->get('https://www.example.com/');
If you're using a library that uses psr/log getting up and runniing with PHPDebugConsole couldn't be easier.
logger method | maps to |
---|---|
$logger->emergency() |
$debug->error() |
$logger->alert() |
$debug->alert() |
$logger->critical() |
$debug->error() |
$logger->error() |
$debug->error() |
$logger->warning() |
$debug->warn() |
$logger->notice() |
$debug->warn() |
$logger->info() |
$debug->info() |
$logger->debug() |
$debug->log() |
$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');
$cache = new \bdk\Debug\Collector\SimpleCache($someSimpleCacheImplementation);
$cache->get('twitterFeed');
/*
Use the PHPDebugConsole SoapClient class (extends SoapClient)
*/
$wsdl = 'http://www.SoapClient.com/xml/SQLDataSoap.wsdl';
$soapClient = new \bdk\Debug\Collector\SoapClient($wsdl);
/*
Initialize Swift Mailer
*/
$transport = new Swift_SendmailTransport('/usr/sbin/sendmail -bs');
$mailer = new Swift_Mailer($transport);
/*
After initializing Swift Mailer, add Logger Plugin
*/
$logger = new \bdk\Debug\Collector\SwiftMailerLogger();
$mailer->registerPlugin($logger);
/*
Send a message
*/
$message = (new Swift_Message('Definitely Not Spam'))
->setFrom(['bkfake-github@ryahoo.com' => 'Brad Kent'])
->setTo(['randyr@domain.org' => 'Randy Recipient'])
->setBody('Here is the message itself');
$result = $mailer->send($message);
/*
Instantiate Twig
*/
$loader = new Twig_Loader_Filesystem(__DIR__);
$twig = new Twig_Environment($loader);
/*
Add PHPDebugConsole's TwigExtension
*/
$twig->addExtension(new \bdk\Debug\Collector\TwigExtension());
echo $twig->render('test.twig', array(
'name' => 'Test',
));
Debug object provides a writeToResponse method for outputting debug to PSR-7 response or HttpFoundation response object.
See writeToResponse for more info.
PHPDebugConsole provides a PSR-15 Middleware you may use in your projects.
/** @var Psr\Http\Server\MiddlewareInterface;*/
$middleware = $debug->middleware;
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
value | |
---|---|
Accept | text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 |
Accept-Encoding | gzip, deflate, br, zstd |
Accept-Language | en-US,en;q=0.9,fr;q=0.8 |
Cache-Control | max-age=0 |
Connection | keep-alive |
Cookie | debug=backdoor; SESSIONID=dv4ekvip4c56ir34ujq4g7qsk3 |
Dnt | 1 |
Host | local.bradkent.com |
Sec-Ch-Ua | "Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99" |
Sec-Ch-Ua-Mobile | ?0 |
Sec-Ch-Ua-Platform | "macOS" |
Sec-Fetch-Dest | document |
Sec-Fetch-Mode | navigate |
Sec-Fetch-Site | same-origin |
Sec-Fetch-User | ?1 |
Sec-Gpc | 1 |
Upgrade-Insecure-Requests | 1 |
User-Agent | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 |
value | |
---|---|
SESSIONID | dv4ekvip4c56ir34ujq4g7qsk3 |
debug | backdoor |
value | |
---|---|
Content-Type | text/html |
Cookie | SESSIONID=5umr2d3e392f6idhvpadiqs7r0 |