| 1 |
<?php |
| 2 |
/** |
| 3 |
* Kint is a zero-setup debugging tool to output information about variables and stack traces prettily and comfortably. |
| 4 |
* |
| 5 |
* https://github.com/raveren/kint |
| 6 |
*/ |
| 7 |
define( 'KINT_DIR', dirname( __FILE__ ) . '/' ); |
| 8 |
require KINT_DIR . 'config.default.php'; |
| 9 |
require KINT_DIR . 'parsers/parser.class.php'; |
| 10 |
|
| 11 |
if ( is_readable( KINT_DIR . 'config.php' ) ) { |
| 12 |
require KINT_DIR . 'config.php'; |
| 13 |
} |
| 14 |
|
| 15 |
class Kint |
| 16 |
{ |
| 17 |
// these are all public and 1:1 config array keys so you can switch them easily |
| 18 |
public static $traceCleanupCallback; |
| 19 |
public static $fileLinkFormat; |
| 20 |
public static $hideSequentialKeys; |
| 21 |
public static $showClassConstants; |
| 22 |
public static $keyFilterCallback; |
| 23 |
public static $displayCalledFrom; |
| 24 |
public static $charEncodings; |
| 25 |
public static $maxStrLength; |
| 26 |
public static $appRootDirs; |
| 27 |
public static $maxLevels; |
| 28 |
public static $enabled; |
| 29 |
public static $theme; |
| 30 |
public static $expandedByDefault; |
| 31 |
public static $devel; # todo remove |
| 32 |
|
| 33 |
protected static $_firstRun = true; |
| 34 |
|
| 35 |
# non-standard function calls |
| 36 |
protected static $_statements = array( 'include', 'include_once', 'require', 'require_once' ); |
| 37 |
|
| 38 |
/** |
| 39 |
* getter/setter for the enabled parameter, called at the beginning of every public function as getter, also |
| 40 |
* initializes the settings if te first time it's run. |
| 41 |
* |
| 42 |
* @param null $value |
| 43 |
* |
| 44 |
* @return void|bool |
| 45 |
*/ |
| 46 |
public static function enabled( $value = null ) |
| 47 |
{ |
| 48 |
# act both as a setter... |
| 49 |
if ( func_num_args() > 0 ) { |
| 50 |
self::$enabled = $value; |
| 51 |
return; |
| 52 |
} |
| 53 |
|
| 54 |
# ...and a getter |
| 55 |
return self::$enabled; |
| 56 |
} |
| 57 |
|
| 58 |
public static function _init() |
| 59 |
{ |
| 60 |
# init settings |
| 61 |
if ( isset( $GLOBALS['_kint_settings'] ) ) { |
| 62 |
foreach ( $GLOBALS['_kint_settings'] as $key => $val ) { |
| 63 |
self::$$key = $val; |
| 64 |
} |
| 65 |
} |
| 66 |
|
| 67 |
require KINT_DIR . 'decorators/rich.php'; |
| 68 |
require KINT_DIR . 'decorators/concise.php'; |
| 69 |
} |
| 70 |
|
| 71 |
/** |
| 72 |
* Prints a debug backtrace |
| 73 |
* |
| 74 |
* @param array $trace [OPTIONAL] you can pass your own trace, otherwise, `debug_backtrace` will be called |
| 75 |
* |
| 76 |
* @return void |
| 77 |
*/ |
| 78 |
public static function trace( $trace = null ) |
| 79 |
{ |
| 80 |
if ( !Kint::enabled() ) return; |
| 81 |
|
| 82 |
echo Kint_Decorators_Rich::_css(); |
| 83 |
|
| 84 |
isset( $trace ) or $trace = debug_backtrace( true ); |
| 85 |
|
| 86 |
$output = array(); |
| 87 |
foreach ( $trace as $step ) { |
| 88 |
self::$traceCleanupCallback and $step = call_user_func( self::$traceCleanupCallback, $step ); |
| 89 |
|
| 90 |
# if the user defined trace cleanup function returns null, skip this line |
| 91 |
if ( $step === null ) { |
| 92 |
continue; |
| 93 |
} |
| 94 |
|
| 95 |
if ( !isset( $step['function'] ) ) { |
| 96 |
# invalid trace step |
| 97 |
continue; |
| 98 |
} |
| 99 |
|
| 100 |
if ( isset( $step['file'] ) AND isset( $step['line'] ) ) { |
| 101 |
# include the source of this step |
| 102 |
$source = self::_showSource( $step['file'], $step['line'] ); |
| 103 |
} |
| 104 |
|
| 105 |
if ( isset( $step['file'] ) ) { |
| 106 |
$file = $step['file']; |
| 107 |
|
| 108 |
if ( isset( $step['line'] ) ) { |
| 109 |
$line = $step['line']; |
| 110 |
} |
| 111 |
} |
| 112 |
|
| 113 |
|
| 114 |
$function = $step['function']; |
| 115 |
|
| 116 |
if ( in_array( $step['function'], self::$_statements ) ) { |
| 117 |
if ( empty( $step['args'] ) ) { |
| 118 |
# no arguments |
| 119 |
$args = array(); |
| 120 |
} else { |
| 121 |
# sanitize the file path |
| 122 |
$args = array( self::shortenPath( $step['args'][0] ) ); |
| 123 |
} |
| 124 |
} elseif ( isset( $step['args'] ) ) { |
| 125 |
if ( empty( $step['class'] ) && !function_exists( $step['function'] ) ) { |
| 126 |
# introspection on closures or language constructs in a stack trace is impossible before PHP 5.3 |
| 127 |
$params = null; |
| 128 |
} else { |
| 129 |
try { |
| 130 |
if ( isset( $step['class'] ) ) { |
| 131 |
if ( method_exists( $step['class'], $step['function'] ) ) { |
| 132 |
$reflection = new ReflectionMethod( $step['class'], $step['function'] ); |
| 133 |
} else if ( isset( $step['type'] ) && $step['type'] == '::' ) { |
| 134 |
$reflection = new ReflectionMethod( $step['class'], '__callStatic' ); |
| 135 |
} else { |
| 136 |
$reflection = new ReflectionMethod( $step['class'], '__call' ); |
| 137 |
} |
| 138 |
} else { |
| 139 |
$reflection = new ReflectionFunction( $step['function'] ); |
| 140 |
} |
| 141 |
|
| 142 |
# get the function parameters |
| 143 |
$params = $reflection->getParameters(); |
| 144 |
} catch ( Exception $e ) { |
| 145 |
$params = null; # avoid various PHP version incompatibilities |
| 146 |
} |
| 147 |
} |
| 148 |
|
| 149 |
$args = array(); |
| 150 |
foreach ( $step['args'] as $i => $arg ) { |
| 151 |
if ( isset( $params[$i] ) ) { |
| 152 |
# assign the argument by the parameter name |
| 153 |
$args[$params[$i]->name] = $arg; |
| 154 |
} else { |
| 155 |
# assign the argument by number |
| 156 |
$args[$i] = $arg; |
| 157 |
} |
| 158 |
} |
| 159 |
} |
| 160 |
|
| 161 |
if ( isset( $step['class'] ) ) { |
| 162 |
# Class->method() or Class::method() |
| 163 |
$function = $step['class'] . $step['type'] . $step['function']; |
| 164 |
} |
| 165 |
|
| 166 |
if ( isset( $step['object'] ) ) { |
| 167 |
$function = $step['class'] . $step['type'] . $step['function']; |
| 168 |
} |
| 169 |
|
| 170 |
$output[] = array( |
| 171 |
'function' => $function, |
| 172 |
'args' => isset( $args ) ? $args : null, |
| 173 |
'file' => isset( $file ) ? $file : null, |
| 174 |
'line' => isset( $line ) ? $line : null, |
| 175 |
'source' => isset( $source ) ? $source : null, |
| 176 |
'object' => isset( $step['object'] ) ? $step['object'] : null, |
| 177 |
); |
| 178 |
|
| 179 |
unset( $function, $args, $file, $line, $source ); |
| 180 |
} |
| 181 |
|
| 182 |
require KINT_DIR . 'view/trace.phtml'; |
| 183 |
} |
| 184 |
|
| 185 |
/** |
| 186 |
* dump information about variables |
| 187 |
* |
| 188 |
* @param mixed $data |
| 189 |
* |
| 190 |
* @return void|string |
| 191 |
*/ |
| 192 |
public static function dump( $data = null ) |
| 193 |
{ |
| 194 |
if ( !Kint::enabled() ) return; |
| 195 |
|
| 196 |
# find caller information |
| 197 |
$trace = debug_backtrace(); |
| 198 |
list( $names, $modifier, $callee, $previousCaller ) = self::_getPassedNames( $trace ); |
| 199 |
if ( $names === array( null ) && func_num_args() === 1 && $data === 1 ) { |
| 200 |
$call = reset( $trace ); |
| 201 |
if ( !isset( $call['file'] ) && isset( $call['class'] ) && $call['class'] === __CLASS__ ) { |
| 202 |
array_shift( $trace ); |
| 203 |
$call = reset( $trace ); |
| 204 |
} |
| 205 |
|
| 206 |
while ( isset( $call['file'] ) && $call['file'] === __FILE__ ) { |
| 207 |
array_shift( $trace ); |
| 208 |
$call = reset( $trace ); |
| 209 |
} |
| 210 |
|
| 211 |
self::trace( $trace ); |
| 212 |
return; |
| 213 |
} |
| 214 |
|
| 215 |
# process modifiers: @, + and - |
| 216 |
switch ( $modifier ) { |
| 217 |
case '-': |
| 218 |
self::$_firstRun = true; |
| 219 |
while ( ob_get_level() ) { |
| 220 |
ob_end_clean(); |
| 221 |
} |
| 222 |
break; |
| 223 |
|
| 224 |
case '!': |
| 225 |
self::$expandedByDefault = true; |
| 226 |
break; |
| 227 |
case '+': |
| 228 |
$maxLevelsOldValue = self::$maxLevels; |
| 229 |
self::$maxLevels = false; |
| 230 |
break; |
| 231 |
case '@': |
| 232 |
$firstRunOldValue = self::$_firstRun; |
| 233 |
self::$_firstRun = true; |
| 234 |
break; |
| 235 |
} |
| 236 |
|
| 237 |
|
| 238 |
$data = func_num_args() === 0 |
| 239 |
? array( "[[no arguments passed]]" ) |
| 240 |
: func_get_args(); |
| 241 |
|
| 242 |
|
| 243 |
$output = Kint_Decorators_Rich::_css(); |
| 244 |
$output .= Kint_Decorators_Rich::_wrapStart( $callee ); |
| 245 |
|
| 246 |
foreach ( $data as $k => $argument ) { |
| 247 |
$output .= self::_dump( $argument, $names[$k] ); |
| 248 |
} |
| 249 |
$output .= Kint_Decorators_Rich::_wrapEnd( $callee, $previousCaller ); |
| 250 |
|
| 251 |
self::$_firstRun = false; |
| 252 |
|
| 253 |
switch ( $modifier ) { |
| 254 |
case '+': |
| 255 |
self::$maxLevels = $maxLevelsOldValue; |
| 256 |
echo $output; |
| 257 |
break; |
| 258 |
case '@': |
| 259 |
self::$_firstRun = $firstRunOldValue; |
| 260 |
return $output; |
| 261 |
break; |
| 262 |
default: |
| 263 |
echo $output; |
| 264 |
break; |
| 265 |
} |
| 266 |
|
| 267 |
return ''; |
| 268 |
} |
| 269 |
|
| 270 |
protected static function _dump( $var, $name = '' ) |
| 271 |
{ |
| 272 |
kintParser::reset(); |
| 273 |
return Kint_Decorators_Rich::decorate( |
| 274 |
kintParser::factory( $var, $name ) |
| 275 |
); |
| 276 |
} |
| 277 |
|
| 278 |
|
| 279 |
/** |
| 280 |
* generic path display callback, can be configured in the settings |
| 281 |
* |
| 282 |
* @param string $file |
| 283 |
* @param int $line [OPTIONAL] |
| 284 |
* |
| 285 |
* @return string |
| 286 |
*/ |
| 287 |
public static function shortenPath( $file, $line = null ) |
| 288 |
{ |
| 289 |
$file = str_replace( '\\', '/', $file ); |
| 290 |
$shortenedName = $file; |
| 291 |
foreach ( self::$appRootDirs as $path => $replaceString ) { |
| 292 |
$path = str_replace( '\\', '/', $path ); |
| 293 |
|
| 294 |
if ( strpos( $file, $path ) === 0 ) { |
| 295 |
$shortenedName = $replaceString . substr( $file, strlen( $path ) ); |
| 296 |
break; |
| 297 |
} |
| 298 |
} |
| 299 |
|
| 300 |
|
| 301 |
if ( !$line ) { # means this is called from resource type dump |
| 302 |
return $shortenedName; |
| 303 |
} |
| 304 |
|
| 305 |
if ( !self::$fileLinkFormat ) { |
| 306 |
return "{$shortenedName} line <i>{$line}</i>"; |
| 307 |
} |
| 308 |
|
| 309 |
$url = str_replace( array( '%f', '%l' ), array( $file, $line ), self::$fileLinkFormat ); |
| 310 |
$class = ( strpos( $url, 'http://' ) === 0 ) ? 'class="kint-ide-link"' : ''; |
| 311 |
|
| 312 |
return "<u><a {$class} href=\"{$url}\">{$shortenedName}</a></u> line <i>{$line}</i>"; |
| 313 |
} |
| 314 |
|
| 315 |
|
| 316 |
/** |
| 317 |
* trace helper, shows the place in code inline |
| 318 |
* |
| 319 |
* @param string $file full path to file |
| 320 |
* @param int $lineNumber the line to display |
| 321 |
* @param int $padding surrounding lines to show besides the main one |
| 322 |
* |
| 323 |
* @return bool|string |
| 324 |
*/ |
| 325 |
private static function _showSource( $file, $lineNumber, $padding = 7 ) |
| 326 |
{ |
| 327 |
if ( !$file OR !is_readable( $file ) ) { |
| 328 |
# continuing will cause errors |
| 329 |
return false; |
| 330 |
} |
| 331 |
|
| 332 |
# open the file and set the line position |
| 333 |
$file = fopen( $file, 'r' ); |
| 334 |
$line = 0; |
| 335 |
|
| 336 |
# Set the reading range |
| 337 |
$range = array( |
| 338 |
'start' => $lineNumber - $padding, |
| 339 |
'end' => $lineNumber + $padding |
| 340 |
); |
| 341 |
|
| 342 |
# set the zero-padding amount for line numbers |
| 343 |
$format = '% ' . strlen( $range['end'] ) . 'd'; |
| 344 |
|
| 345 |
$source = ''; |
| 346 |
while ( ( $row = fgets( $file ) ) !== false ) { |
| 347 |
# increment the line number |
| 348 |
if ( ++$line > $range['end'] ) { |
| 349 |
break; |
| 350 |
} |
| 351 |
|
| 352 |
if ( $line >= $range['start'] ) { |
| 353 |
# make the row safe for output |
| 354 |
$row = htmlspecialchars( $row, ENT_NOQUOTES ); |
| 355 |
|
| 356 |
# trim whitespace and sanitize the row |
| 357 |
$row = '<span>' . sprintf( $format, $line ) . '</span> ' . $row; |
| 358 |
|
| 359 |
if ( $line === $lineNumber ) { |
| 360 |
# apply highlighting to this row |
| 361 |
$row = '<div class="kint-highlight">' . $row . '</div>'; |
| 362 |
} else { |
| 363 |
$row = '<div>' . $row . '</div>'; |
| 364 |
} |
| 365 |
|
| 366 |
# add to the captured source |
| 367 |
$source .= $row; |
| 368 |
} |
| 369 |
} |
| 370 |
|
| 371 |
# close the file |
| 372 |
fclose( $file ); |
| 373 |
|
| 374 |
return $source; |
| 375 |
} |
| 376 |
|
| 377 |
|
| 378 |
/** |
| 379 |
* returns parameter names that the function was passed, as well as any predefined symbols before function |
| 380 |
* call (modifiers) |
| 381 |
* |
| 382 |
* @param array $trace |
| 383 |
* |
| 384 |
* @return array( $parameters, $modifier, $callee, $previousCaller ) |
| 385 |
*/ |
| 386 |
private static function _getPassedNames( $trace ) |
| 387 |
{ |
| 388 |
$previousCaller = array(); |
| 389 |
while ( $callee = array_pop( $trace ) ) { |
| 390 |
if ( strtolower( $callee['function'] ) === 'd' || |
| 391 |
strtolower( $callee['function'] ) === 'dd' || |
| 392 |
( isset( $callee['class'] ) && strtolower( $callee['class'] ) === strtolower( __CLASS__ ) |
| 393 |
&& strtolower( $callee['function'] ) === 'dump' ) |
| 394 |
) { |
| 395 |
break; |
| 396 |
} else { |
| 397 |
$previousCaller = $callee; |
| 398 |
} |
| 399 |
} |
| 400 |
|
| 401 |
if ( !isset( $callee['file'] ) || !is_readable( $callee['file'] ) ) { |
| 402 |
return false; |
| 403 |
} |
| 404 |
|
| 405 |
# open the file and read it up to the position where the function call expression ended |
| 406 |
$file = fopen( $callee['file'], 'r' ); |
| 407 |
$line = 0; |
| 408 |
$source = ''; |
| 409 |
while ( ( $row = fgets( $file ) ) !== false ) { |
| 410 |
if ( ++$line > $callee['line'] ) break; |
| 411 |
$source .= $row; |
| 412 |
} |
| 413 |
fclose( $file ); |
| 414 |
$source = self::_removeAllButCode( $source ); |
| 415 |
|
| 416 |
|
| 417 |
$codePattern = empty( $callee['class'] ) |
| 418 |
? $callee['function'] |
| 419 |
: $callee['class'] . "\x07*" . $callee['type'] . "\x07*" . $callee['function']; |
| 420 |
# get the position of the last call to the function |
| 421 |
preg_match_all( "#[\x07{(](\\+|-|!|@)?{$codePattern}\x07*(\\()#i", $source, $matches, PREG_OFFSET_CAPTURE ); |
| 422 |
$match = end( $matches[2] ); |
| 423 |
$modifier = end( $matches[1] ); |
| 424 |
$modifier = $modifier[0]; |
| 425 |
|
| 426 |
$passedParameters = str_replace( "\x07", '', substr( $source, $match[1] + 1 ) ); |
| 427 |
# we now have a string like this: |
| 428 |
# <parameters passed>); <the rest of the last read line> |
| 429 |
|
| 430 |
# remove everything in brackets and quotes, we don't need nested statements nor literal strings which would |
| 431 |
# only complicate separating individual arguments |
| 432 |
$c = strlen( $passedParameters ); |
| 433 |
$inString = $escaped = false; |
| 434 |
$i = 0; |
| 435 |
$inBrackets = 0; |
| 436 |
while ( $i < $c ) { |
| 437 |
$letter = $passedParameters[$i]; |
| 438 |
if ( $inString === false ) { |
| 439 |
if ( $letter === '\'' || $letter === '"' ) { |
| 440 |
$inString = $letter; |
| 441 |
} elseif ( $letter === '(' ) { |
| 442 |
$inBrackets++; |
| 443 |
} elseif ( $letter === ')' ) { |
| 444 |
$inBrackets--; |
| 445 |
if ( $inBrackets === -1 ) { # this means we are out of the brackets that denote passed parameters |
| 446 |
$passedParameters = substr( $passedParameters, 0, $i ); |
| 447 |
break; |
| 448 |
} |
| 449 |
} |
| 450 |
} elseif ( $letter === $inString && !$escaped ) { |
| 451 |
$inString = false; |
| 452 |
} |
| 453 |
|
| 454 |
# place an untype-able character instead of whatever was inside quotes or brackets, we don't |
| 455 |
# need that info. We'll later replace it with '...' |
| 456 |
if ( $inBrackets > 0 ) { |
| 457 |
if ( $inBrackets > 1 || $letter !== '(' ) { |
| 458 |
$passedParameters[$i] = "\x07"; |
| 459 |
} |
| 460 |
} |
| 461 |
if ( $inString !== false ) { |
| 462 |
if ( $letter !== $inString || $escaped ) { |
| 463 |
$passedParameters[$i] = "\x07"; |
| 464 |
} |
| 465 |
} |
| 466 |
|
| 467 |
$escaped = !$escaped && ( $letter === '\\' ); |
| 468 |
$i++; |
| 469 |
} |
| 470 |
|
| 471 |
# by now we have an unnested arguments list, lets make it to an array for processing further |
| 472 |
$arguments = explode( ',', preg_replace( "#\x07+#", '...', $passedParameters ) ); |
| 473 |
|
| 474 |
# test each argument whether it was passed literary or was it an expression or a variable name |
| 475 |
$parameters = array(); |
| 476 |
$blacklist = array( 'null', 'true', 'false', 'array(...)', 'array()', '"..."', 'b"..."', ); |
| 477 |
foreach ( $arguments as $argument ) { |
| 478 |
|
| 479 |
if ( is_numeric( $argument ) |
| 480 |
|| in_array( str_replace( "'", '"', strtolower( $argument ) ), $blacklist, true ) |
| 481 |
) { |
| 482 |
$parameters[] = null; |
| 483 |
} else { |
| 484 |
$parameters[] = trim( $argument ); |
| 485 |
} |
| 486 |
} |
| 487 |
|
| 488 |
return array( $parameters, $modifier, $callee, $previousCaller ); |
| 489 |
} |
| 490 |
|
| 491 |
/** |
| 492 |
* removes comments and zaps whitespace & <?php tags from php code, makes for easier further parsing |
| 493 |
* |
| 494 |
* @param string $source |
| 495 |
* |
| 496 |
* @return string |
| 497 |
*/ |
| 498 |
private static function _removeAllButCode( $source ) |
| 499 |
{ |
| 500 |
$newStr = ''; |
| 501 |
$tokens = token_get_all( $source ); |
| 502 |
$commentTokens = array( T_COMMENT => true, T_INLINE_HTML => true, T_DOC_COMMENT => true ); |
| 503 |
|
| 504 |
defined( 'T_NS_SEPARATOR' ) or define( 'T_NS_SEPARATOR', 380 ); |
| 505 |
|
| 506 |
$whiteSpaceTokens = array( |
| 507 |
T_WHITESPACE => true, T_CLOSE_TAG => true, |
| 508 |
T_OPEN_TAG => true, T_OPEN_TAG_WITH_ECHO => true, |
| 509 |
); |
| 510 |
|
| 511 |
foreach ( $tokens as $token ) { |
| 512 |
if ( is_array( $token ) ) { |
| 513 |
if ( isset( $commentTokens[$token[0]] ) ) continue; |
| 514 |
|
| 515 |
if ( $token[0] === T_NEW ) { |
| 516 |
$token = 'new '; |
| 517 |
} elseif ( $token[0] === T_NS_SEPARATOR ) { |
| 518 |
$token = "\\\x07"; |
| 519 |
} elseif ( isset( $whiteSpaceTokens[$token[0]] ) ) { |
| 520 |
$token = "\x07"; |
| 521 |
} else { |
| 522 |
$token = $token[1]; |
| 523 |
} |
| 524 |
} elseif ( $token === ';' ) { |
| 525 |
$token = "\x07"; |
| 526 |
} |
| 527 |
|
| 528 |
$newStr .= $token; |
| 529 |
} |
| 530 |
return $newStr; |
| 531 |
} |
| 532 |
} |
| 533 |
|
| 534 |
|
| 535 |
if ( !function_exists( 'd' ) ) { |
| 536 |
/** |
| 537 |
* Alias of Kint::dump() |
| 538 |
* |
| 539 |
* @return string |
| 540 |
*/ |
| 541 |
function d() |
| 542 |
{ |
| 543 |
if ( !Kint::enabled() ) return null; |
| 544 |
|
| 545 |
$args = func_get_args(); |
| 546 |
return call_user_func_array( array( 'Kint', 'dump' ), $args ); |
| 547 |
} |
| 548 |
} |
| 549 |
|
| 550 |
if ( !function_exists( 'dd' ) ) { |
| 551 |
/** |
| 552 |
* Alias of Kint::dump() |
| 553 |
* [!!!] IMPORTANT: execution will halt after call to this function |
| 554 |
* |
| 555 |
* @return string |
| 556 |
*/ |
| 557 |
function dd() |
| 558 |
{ |
| 559 |
if ( !Kint::enabled() ) return; |
| 560 |
|
| 561 |
$args = func_get_args(); |
| 562 |
call_user_func_array( array( 'Kint', 'dump' ), $args ); |
| 563 |
die; |
| 564 |
} |
| 565 |
} |
| 566 |
|
| 567 |
if ( !function_exists( 's' ) ) { |
| 568 |
|
| 569 |
/** |
| 570 |
* Alias of kintLite() |
| 571 |
* |
| 572 |
* @return string |
| 573 |
*/ |
| 574 |
function s() |
| 575 |
{ |
| 576 |
if ( !Kint::enabled() ) return; |
| 577 |
|
| 578 |
$argv = func_get_args(); |
| 579 |
echo '<pre>'; |
| 580 |
foreach ( $argv as $k => $v ) { |
| 581 |
$k && print( "\n\n" ); |
| 582 |
echo kintLite( $v ); |
| 583 |
} |
| 584 |
echo '</pre>' . "\n"; |
| 585 |
} |
| 586 |
|
| 587 |
/** |
| 588 |
* Alias of kintLite() |
| 589 |
* [!!!] IMPORTANT: execution will halt after call to this function |
| 590 |
* |
| 591 |
* @return string |
| 592 |
*/ |
| 593 |
function sd() |
| 594 |
{ |
| 595 |
if ( !Kint::enabled() ) return; |
| 596 |
|
| 597 |
echo '<pre>'; |
| 598 |
foreach ( func_get_args() as $k => $v ) { |
| 599 |
$k && print( "\n\n" ); |
| 600 |
echo kintLite( $v ); |
| 601 |
} |
| 602 |
echo '</pre>'; |
| 603 |
die; |
| 604 |
|
| 605 |
} |
| 606 |
|
| 607 |
} |
| 608 |
|
| 609 |
if (!function_exists('kintLite')) { |
| 610 |
/** |
| 611 |
* lightweight version of Kint::dump(). Uses whitespace for formatting instead of html |
| 612 |
* sadly not DRY yet |
| 613 |
* |
| 614 |
* @param $var |
| 615 |
* @param int $level |
| 616 |
* |
| 617 |
* @return string |
| 618 |
*/ |
| 619 |
function kintLite( &$var, $level = 0 ) |
| 620 |
{ |
| 621 |
|
| 622 |
// initialize function names into variables for prettier string output (html and implode are also DRY) |
| 623 |
$html = "htmlspecialchars"; |
| 624 |
$implode = "implode"; |
| 625 |
$strlen = "strlen"; |
| 626 |
$count = "count"; |
| 627 |
$getClass = "get_class"; |
| 628 |
|
| 629 |
|
| 630 |
if ( $var === null ) { |
| 631 |
return 'NULL'; |
| 632 |
} elseif ( is_bool( $var ) ) { |
| 633 |
return 'bool ' . ( $var ? 'TRUE' : 'FALSE' ); |
| 634 |
} elseif ( is_float( $var ) ) { |
| 635 |
return 'float ' . $var; |
| 636 |
} elseif ( is_int( $var ) ) { |
| 637 |
return 'integer ' . $var; |
| 638 |
} elseif ( is_resource( $var ) ) { |
| 639 |
if ( ( $type = get_resource_type( $var ) ) === 'stream' AND $meta = stream_get_meta_data( $var ) ) { |
| 640 |
|
| 641 |
if ( isset( $meta['uri'] ) ) { |
| 642 |
$file = $meta['uri']; |
| 643 |
|
| 644 |
return "resource ({$type}) {$html( $file, 0 )}"; |
| 645 |
} else { |
| 646 |
return "resource ({$type})"; |
| 647 |
} |
| 648 |
} else { |
| 649 |
return "resource ({$type})"; |
| 650 |
} |
| 651 |
} elseif ( is_string( $var ) ) { |
| 652 |
return "string ({$strlen( $var )}) \"{$html( $var )}\""; |
| 653 |
} elseif ( is_array( $var ) ) { |
| 654 |
$output = array(); |
| 655 |
$space = str_repeat( $s = ' ', $level ); |
| 656 |
|
| 657 |
static $marker; |
| 658 |
|
| 659 |
if ( $marker === null ) { |
| 660 |
// Make a unique marker |
| 661 |
$marker = uniqid( "\x00" ); |
| 662 |
} |
| 663 |
|
| 664 |
if ( empty( $var ) ) { |
| 665 |
return "array()"; |
| 666 |
} elseif ( isset( $var[$marker] ) ) { |
| 667 |
$output[] = "[\n$space$s*RECURSION*\n$space]"; |
| 668 |
} elseif ( $level < 7 ) { |
| 669 |
$isSeq = array_keys( $var ) === range( 0, count( $var ) - 1 ); |
| 670 |
|
| 671 |
$output[] = "["; |
| 672 |
|
| 673 |
$var[$marker] = true; |
| 674 |
|
| 675 |
|
| 676 |
foreach ( $var as $key => &$val ) { |
| 677 |
if ( $key === $marker ) continue; |
| 678 |
|
| 679 |
$key = $space . $s . ( $isSeq ? "" : "'{$html( $key, 0 )}' => " ); |
| 680 |
|
| 681 |
$dump = kintLite( $val, $level + 1 ); |
| 682 |
$output[] = "{$key}{$dump}"; |
| 683 |
} |
| 684 |
|
| 685 |
unset( $var[$marker] ); |
| 686 |
$output[] = "$space]"; |
| 687 |
|
| 688 |
} else { |
| 689 |
$output[] = "[\n$space$s*depth too great*\n$space]"; |
| 690 |
} |
| 691 |
return "array({$count( $var )}) {$implode( "\n", $output )}"; |
| 692 |
} elseif ( is_object( $var ) ) { |
| 693 |
if ( $var instanceof SplFileInfo ) { |
| 694 |
return "object SplFileInfo " . $var->getRealPath(); |
| 695 |
} |
| 696 |
|
| 697 |
// Copy the object as an array |
| 698 |
$array = (array)$var; |
| 699 |
|
| 700 |
$output = array(); |
| 701 |
$space = str_repeat( $s = ' ', $level ); |
| 702 |
|
| 703 |
$hash = spl_object_hash( $var ); |
| 704 |
|
| 705 |
// Objects that are being dumped |
| 706 |
static $objects = array(); |
| 707 |
|
| 708 |
if ( empty( $array ) ) { |
| 709 |
return "object {$getClass( $var )} {}"; |
| 710 |
} elseif ( isset( $objects[$hash] ) ) { |
| 711 |
$output[] = "{\n$space$s*RECURSION*\n$space}"; |
| 712 |
} elseif ( $level < 7 ) { |
| 713 |
$output[] = "{"; |
| 714 |
$objects[$hash] = true; |
| 715 |
|
| 716 |
foreach ( $array as $key => & $val ) { |
| 717 |
if ( $key[0] === "\x00" ) { |
| 718 |
|
| 719 |
$access = $key[1] === "*" ? "protected" : "private"; |
| 720 |
|
| 721 |
// Remove the access level from the variable name |
| 722 |
$key = substr( $key, strrpos( $key, "\x00" ) + 1 ); |
| 723 |
} else { |
| 724 |
$access = "public"; |
| 725 |
} |
| 726 |
|
| 727 |
$output[] = "$space$s$access $key -> " . kintLite( $val, $level + 1 ); |
| 728 |
} |
| 729 |
unset( $objects[$hash] ); |
| 730 |
$output[] = "$space}"; |
| 731 |
|
| 732 |
} else { |
| 733 |
$output[] = "{\n$space$s*depth too great*\n$space}"; |
| 734 |
} |
| 735 |
|
| 736 |
return "object {$getClass( $var )} ({$count( $array )}) {$implode( "\n", $output )}"; |
| 737 |
} else { |
| 738 |
return gettype( $var ) . htmlspecialchars( var_export( $var, true ), ENT_NOQUOTES ); |
| 739 |
} |
| 740 |
} |
| 741 |
} |
| 742 |
Kint::_init(); |
| 743 |
|