| 1: | <?php | 
| 2: |  | 
| 3: |  | 
| 4: |  | 
| 5: |  | 
| 6: |  | 
| 7: |  | 
| 8: |  | 
| 9: |  | 
| 10: |  | 
| 11: |  | 
| 12: |  | 
| 13: |  | 
| 14: |  | 
| 15: |  | 
| 16: |  | 
| 17: |  | 
| 18: |  | 
| 19: |  | 
| 20: |  | 
| 21: |  | 
| 22: |  | 
| 23: |  | 
| 24: |  | 
| 25: |  | 
| 26: | namespace Kint; | 
| 27: |  | 
| 28: | use InvalidArgumentException; | 
| 29: | use Kint\Object\BasicObject; | 
| 30: | use Kint\Parser\Parser; | 
| 31: | use Kint\Parser\Plugin; | 
| 32: | use Kint\Renderer\Renderer; | 
| 33: | use Kint\Renderer\TextRenderer; | 
| 34: |  | 
| 35: | class Kint | 
| 36: | { | 
| 37: | const MODE_RICH = 'r'; | 
| 38: | const MODE_TEXT = 't'; | 
| 39: | const MODE_CLI = 'c'; | 
| 40: | const MODE_PLAIN = 'p'; | 
| 41: |  | 
| 42: |  | 
| 43: |  | 
| 44: |  | 
| 45: |  | 
| 46: |  | 
| 47: |  | 
| 48: |  | 
| 49: | public static $enabled_mode = true; | 
| 50: |  | 
| 51: |  | 
| 52: |  | 
| 53: |  | 
| 54: |  | 
| 55: |  | 
| 56: | public static $mode_default = self::MODE_RICH; | 
| 57: |  | 
| 58: |  | 
| 59: |  | 
| 60: |  | 
| 61: |  | 
| 62: |  | 
| 63: | public static $mode_default_cli = self::MODE_CLI; | 
| 64: |  | 
| 65: |  | 
| 66: |  | 
| 67: |  | 
| 68: | public static $return; | 
| 69: |  | 
| 70: |  | 
| 71: |  | 
| 72: |  | 
| 73: |  | 
| 74: |  | 
| 75: |  | 
| 76: |  | 
| 77: |  | 
| 78: |  | 
| 79: | public static $file_link_format = ''; | 
| 80: |  | 
| 81: |  | 
| 82: |  | 
| 83: |  | 
| 84: | public static $display_called_from = true; | 
| 85: |  | 
| 86: |  | 
| 87: |  | 
| 88: |  | 
| 89: |  | 
| 90: |  | 
| 91: |  | 
| 92: |  | 
| 93: |  | 
| 94: |  | 
| 95: |  | 
| 96: |  | 
| 97: |  | 
| 98: |  | 
| 99: |  | 
| 100: |  | 
| 101: |  | 
| 102: |  | 
| 103: |  | 
| 104: |  | 
| 105: | public static $app_root_dirs = array(); | 
| 106: |  | 
| 107: |  | 
| 108: |  | 
| 109: |  | 
| 110: | public static $max_depth = 6; | 
| 111: |  | 
| 112: |  | 
| 113: |  | 
| 114: |  | 
| 115: | public static $expanded = false; | 
| 116: |  | 
| 117: |  | 
| 118: |  | 
| 119: |  | 
| 120: |  | 
| 121: |  | 
| 122: | public static $cli_detection = true; | 
| 123: |  | 
| 124: |  | 
| 125: |  | 
| 126: |  | 
| 127: | public static $aliases = array( | 
| 128: | array('Kint\\Kint', 'dump'), | 
| 129: | array('Kint\\Kint', 'trace'), | 
| 130: | array('Kint\\Kint', 'dumpArray'), | 
| 131: | ); | 
| 132: |  | 
| 133: |  | 
| 134: |  | 
| 135: |  | 
| 136: | public static $renderers = array( | 
| 137: | self::MODE_RICH => 'Kint\\Renderer\\RichRenderer', | 
| 138: | self::MODE_PLAIN => 'Kint\\Renderer\\PlainRenderer', | 
| 139: | self::MODE_TEXT => 'Kint\\Renderer\\TextRenderer', | 
| 140: | self::MODE_CLI => 'Kint\\Renderer\\CliRenderer', | 
| 141: | ); | 
| 142: |  | 
| 143: | public static $plugins = array( | 
| 144: | 'Kint\\Parser\\ArrayObjectPlugin', | 
| 145: | 'Kint\\Parser\\Base64Plugin', | 
| 146: | 'Kint\\Parser\\BlacklistPlugin', | 
| 147: | 'Kint\\Parser\\ClassMethodsPlugin', | 
| 148: | 'Kint\\Parser\\ClassStaticsPlugin', | 
| 149: | 'Kint\\Parser\\ClosurePlugin', | 
| 150: | 'Kint\\Parser\\ColorPlugin', | 
| 151: | 'Kint\\Parser\\DateTimePlugin', | 
| 152: | 'Kint\\Parser\\FsPathPlugin', | 
| 153: | 'Kint\\Parser\\IteratorPlugin', | 
| 154: | 'Kint\\Parser\\JsonPlugin', | 
| 155: | 'Kint\\Parser\\MicrotimePlugin', | 
| 156: | 'Kint\\Parser\\SimpleXMLElementPlugin', | 
| 157: | 'Kint\\Parser\\SplFileInfoPlugin', | 
| 158: | 'Kint\\Parser\\SplObjectStoragePlugin', | 
| 159: | 'Kint\\Parser\\StreamPlugin', | 
| 160: | 'Kint\\Parser\\TablePlugin', | 
| 161: | 'Kint\\Parser\\ThrowablePlugin', | 
| 162: | 'Kint\\Parser\\TimestampPlugin', | 
| 163: | 'Kint\\Parser\\TracePlugin', | 
| 164: | 'Kint\\Parser\\XmlPlugin', | 
| 165: | ); | 
| 166: |  | 
| 167: | protected static $plugin_pool = array(); | 
| 168: |  | 
| 169: | protected $parser; | 
| 170: | protected $renderer; | 
| 171: |  | 
| 172: | public function __construct(Parser $p, Renderer $r) | 
| 173: | { | 
| 174: | $this->parser = $p; | 
| 175: | $this->renderer = $r; | 
| 176: | } | 
| 177: |  | 
| 178: | public function setParser(Parser $p) | 
| 179: | { | 
| 180: | $this->parser = $p; | 
| 181: | } | 
| 182: |  | 
| 183: | public function getParser() | 
| 184: | { | 
| 185: | return $this->parser; | 
| 186: | } | 
| 187: |  | 
| 188: | public function setRenderer(Renderer $r) | 
| 189: | { | 
| 190: | $this->renderer = $r; | 
| 191: | } | 
| 192: |  | 
| 193: | public function getRenderer() | 
| 194: | { | 
| 195: | return $this->renderer; | 
| 196: | } | 
| 197: |  | 
| 198: | public function setStatesFromStatics(array $statics) | 
| 199: | { | 
| 200: | $this->renderer->setStatics($statics); | 
| 201: |  | 
| 202: | $this->parser->setDepthLimit(isset($statics['max_depth']) ? $statics['max_depth'] : false); | 
| 203: | $this->parser->clearPlugins(); | 
| 204: |  | 
| 205: | if (!isset($statics['plugins'])) { | 
| 206: | return; | 
| 207: | } | 
| 208: |  | 
| 209: | $plugins = array(); | 
| 210: |  | 
| 211: | foreach ($statics['plugins'] as $plugin) { | 
| 212: | if ($plugin instanceof Plugin) { | 
| 213: | $plugins[] = $plugin; | 
| 214: | } elseif (\is_string($plugin) && \is_subclass_of($plugin, 'Kint\\Parser\\Plugin')) { | 
| 215: | if (!isset(self::$plugin_pool[$plugin])) { | 
| 216: | $p = new $plugin(); | 
| 217: | self::$plugin_pool[$plugin] = $p; | 
| 218: | } | 
| 219: | $plugins[] = self::$plugin_pool[$plugin]; | 
| 220: | } | 
| 221: | } | 
| 222: |  | 
| 223: | $plugins = $this->renderer->filterParserPlugins($plugins); | 
| 224: |  | 
| 225: | foreach ($plugins as $plugin) { | 
| 226: | $this->parser->addPlugin($plugin); | 
| 227: | } | 
| 228: | } | 
| 229: |  | 
| 230: | public function setStatesFromCallInfo(array $info) | 
| 231: | { | 
| 232: | $this->renderer->setCallInfo($info); | 
| 233: |  | 
| 234: | if (isset($info['modifiers']) && \is_array($info['modifiers']) && \in_array('+', $info['modifiers'], true)) { | 
| 235: | $this->parser->setDepthLimit(false); | 
| 236: | } | 
| 237: |  | 
| 238: | $this->parser->setCallerClass(isset($info['caller']['class']) ? $info['caller']['class'] : null); | 
| 239: | } | 
| 240: |  | 
| 241: |  | 
| 242: |  | 
| 243: |  | 
| 244: |  | 
| 245: |  | 
| 246: |  | 
| 247: |  | 
| 248: |  | 
| 249: | public function dumpAll(array $vars, array $base) | 
| 250: | { | 
| 251: | if (\array_keys($vars) !== \array_keys($base)) { | 
| 252: | throw new InvalidArgumentException('Kint::dumpAll requires arrays of identical size and keys as arguments'); | 
| 253: | } | 
| 254: |  | 
| 255: | $output = $this->renderer->preRender(); | 
| 256: |  | 
| 257: | if ($vars === array()) { | 
| 258: | $output .= $this->renderer->renderNothing(); | 
| 259: | } | 
| 260: |  | 
| 261: | foreach ($vars as $key => $arg) { | 
| 262: | if (!$base[$key] instanceof BasicObject) { | 
| 263: | throw new InvalidArgumentException('Kint::dumpAll requires all elements of the second argument to be BasicObject instances'); | 
| 264: | } | 
| 265: | $output .= $this->dumpVar($arg, $base[$key]); | 
| 266: | } | 
| 267: |  | 
| 268: | $output .= $this->renderer->postRender(); | 
| 269: |  | 
| 270: | return $output; | 
| 271: | } | 
| 272: |  | 
| 273: |  | 
| 274: |  | 
| 275: |  | 
| 276: |  | 
| 277: |  | 
| 278: |  | 
| 279: |  | 
| 280: |  | 
| 281: | public function dumpVar(&$var, BasicObject $base) | 
| 282: | { | 
| 283: | return $this->renderer->render( | 
| 284: | $this->parser->parse($var, $base) | 
| 285: | ); | 
| 286: | } | 
| 287: |  | 
| 288: |  | 
| 289: |  | 
| 290: |  | 
| 291: |  | 
| 292: |  | 
| 293: | public static function getStatics() | 
| 294: | { | 
| 295: | return array( | 
| 296: | 'aliases' => self::$aliases, | 
| 297: | 'app_root_dirs' => self::$app_root_dirs, | 
| 298: | 'cli_detection' => self::$cli_detection, | 
| 299: | 'display_called_from' => self::$display_called_from, | 
| 300: | 'enabled_mode' => self::$enabled_mode, | 
| 301: | 'expanded' => self::$expanded, | 
| 302: | 'file_link_format' => self::$file_link_format, | 
| 303: | 'max_depth' => self::$max_depth, | 
| 304: | 'mode_default' => self::$mode_default, | 
| 305: | 'mode_default_cli' => self::$mode_default_cli, | 
| 306: | 'plugins' => self::$plugins, | 
| 307: | 'renderers' => self::$renderers, | 
| 308: | 'return' => self::$return, | 
| 309: | ); | 
| 310: | } | 
| 311: |  | 
| 312: |  | 
| 313: |  | 
| 314: |  | 
| 315: |  | 
| 316: |  | 
| 317: |  | 
| 318: |  | 
| 319: |  | 
| 320: |  | 
| 321: | public static function createFromStatics(array $statics) | 
| 322: | { | 
| 323: | $mode = false; | 
| 324: |  | 
| 325: | if (isset($statics['enabled_mode'])) { | 
| 326: | $mode = $statics['enabled_mode']; | 
| 327: |  | 
| 328: | if (true === $statics['enabled_mode'] && isset($statics['mode_default'])) { | 
| 329: | $mode = $statics['mode_default']; | 
| 330: |  | 
| 331: | if (PHP_SAPI === 'cli' && !empty($statics['cli_detection']) && isset($statics['mode_default_cli'])) { | 
| 332: | $mode = $statics['mode_default_cli']; | 
| 333: | } | 
| 334: | } | 
| 335: | } | 
| 336: |  | 
| 337: | if (!$mode) { | 
| 338: | return null; | 
| 339: | } | 
| 340: |  | 
| 341: | if (!isset($statics['renderers'][$mode])) { | 
| 342: | $renderer = new TextRenderer(); | 
| 343: | } else { | 
| 344: |  | 
| 345: | $renderer = new $statics['renderers'][$mode](); | 
| 346: | } | 
| 347: |  | 
| 348: | return new self(new Parser(), $renderer); | 
| 349: | } | 
| 350: |  | 
| 351: |  | 
| 352: |  | 
| 353: |  | 
| 354: |  | 
| 355: |  | 
| 356: |  | 
| 357: |  | 
| 358: |  | 
| 359: | public static function getBasesFromParamInfo(array $params, $argc) | 
| 360: | { | 
| 361: | static $blacklist = array( | 
| 362: | 'null', | 
| 363: | 'true', | 
| 364: | 'false', | 
| 365: | 'array(...)', | 
| 366: | 'array()', | 
| 367: | '[...]', | 
| 368: | '[]', | 
| 369: | '(...)', | 
| 370: | '()', | 
| 371: | '"..."', | 
| 372: | 'b"..."', | 
| 373: | "'...'", | 
| 374: | "b'...'", | 
| 375: | ); | 
| 376: |  | 
| 377: | $params = \array_values($params); | 
| 378: | $bases = array(); | 
| 379: |  | 
| 380: | for ($i = 0; $i < $argc; ++$i) { | 
| 381: | if (isset($params[$i])) { | 
| 382: | $param = $params[$i]; | 
| 383: | } else { | 
| 384: | $param = null; | 
| 385: | } | 
| 386: |  | 
| 387: | if (!isset($param['name']) || \is_numeric($param['name'])) { | 
| 388: | $name = null; | 
| 389: | } elseif (\in_array(\strtolower($param['name']), $blacklist, true)) { | 
| 390: | $name = null; | 
| 391: | } else { | 
| 392: | $name = $param['name']; | 
| 393: | } | 
| 394: |  | 
| 395: | if (isset($param['path'])) { | 
| 396: | $access_path = $param['path']; | 
| 397: |  | 
| 398: | if (!empty($param['expression'])) { | 
| 399: | $access_path = '('.$access_path.')'; | 
| 400: | } | 
| 401: | } else { | 
| 402: | $access_path = '$'.$i; | 
| 403: | } | 
| 404: |  | 
| 405: | $bases[] = BasicObject::blank($name, $access_path); | 
| 406: | } | 
| 407: |  | 
| 408: | return $bases; | 
| 409: | } | 
| 410: |  | 
| 411: |  | 
| 412: |  | 
| 413: |  | 
| 414: |  | 
| 415: |  | 
| 416: |  | 
| 417: |  | 
| 418: |  | 
| 419: |  | 
| 420: |  | 
| 421: |  | 
| 422: | public static function getCallInfo(array $aliases, array $trace, $argc) | 
| 423: | { | 
| 424: | $found = false; | 
| 425: | $callee = null; | 
| 426: | $caller = null; | 
| 427: | $miniTrace = array(); | 
| 428: |  | 
| 429: | foreach ($trace as $index => $frame) { | 
| 430: | if (Utils::traceFrameIsListed($frame, $aliases)) { | 
| 431: | $found = true; | 
| 432: | $miniTrace = array(); | 
| 433: | } | 
| 434: |  | 
| 435: | if (!Utils::traceFrameIsListed($frame, array('spl_autoload_call'))) { | 
| 436: | $miniTrace[] = $frame; | 
| 437: | } | 
| 438: | } | 
| 439: |  | 
| 440: | if ($found) { | 
| 441: | $callee = \reset($miniTrace) ?: null; | 
| 442: |  | 
| 443: |  | 
| 444: | $caller = \next($miniTrace) ?: null; | 
| 445: | } | 
| 446: |  | 
| 447: | foreach ($miniTrace as $index => $frame) { | 
| 448: | if ((0 === $index && $callee === $frame) || isset($frame['file'], $frame['line'])) { | 
| 449: | unset($frame['object'], $frame['args']); | 
| 450: | $miniTrace[$index] = $frame; | 
| 451: | } else { | 
| 452: | unset($miniTrace[$index]); | 
| 453: | } | 
| 454: | } | 
| 455: |  | 
| 456: | $miniTrace = \array_values($miniTrace); | 
| 457: |  | 
| 458: | $call = self::getSingleCall($callee ?: array(), $argc); | 
| 459: |  | 
| 460: | $ret = array( | 
| 461: | 'params' => null, | 
| 462: | 'modifiers' => array(), | 
| 463: | 'callee' => $callee, | 
| 464: | 'caller' => $caller, | 
| 465: | 'trace' => $miniTrace, | 
| 466: | ); | 
| 467: |  | 
| 468: | if ($call) { | 
| 469: | $ret['params'] = $call['parameters']; | 
| 470: | $ret['modifiers'] = $call['modifiers']; | 
| 471: | } | 
| 472: |  | 
| 473: | return $ret; | 
| 474: | } | 
| 475: |  | 
| 476: |  | 
| 477: |  | 
| 478: |  | 
| 479: |  | 
| 480: |  | 
| 481: |  | 
| 482: |  | 
| 483: | public static function trace() | 
| 484: | { | 
| 485: | if (!self::$enabled_mode) { | 
| 486: | return 0; | 
| 487: | } | 
| 488: |  | 
| 489: | Utils::normalizeAliases(self::$aliases); | 
| 490: |  | 
| 491: | $args = \func_get_args(); | 
| 492: |  | 
| 493: | $call_info = self::getCallInfo(self::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), \count($args)); | 
| 494: |  | 
| 495: | $statics = self::getStatics(); | 
| 496: |  | 
| 497: | if (\in_array('~', $call_info['modifiers'], true)) { | 
| 498: | $statics['enabled_mode'] = self::MODE_TEXT; | 
| 499: | } | 
| 500: |  | 
| 501: | $kintstance = self::createFromStatics($statics); | 
| 502: | if (!$kintstance) { | 
| 503: |  | 
| 504: | return 0; | 
| 505: | } | 
| 506: |  | 
| 507: | if (\in_array('-', $call_info['modifiers'], true)) { | 
| 508: | while (\ob_get_level()) { | 
| 509: | \ob_end_clean(); | 
| 510: | } | 
| 511: | } | 
| 512: |  | 
| 513: | $kintstance->setStatesFromStatics($statics); | 
| 514: | $kintstance->setStatesFromCallInfo($call_info); | 
| 515: |  | 
| 516: | $trimmed_trace = array(); | 
| 517: | $trace = \debug_backtrace(true); | 
| 518: |  | 
| 519: | foreach ($trace as $frame) { | 
| 520: | if (Utils::traceFrameIsListed($frame, self::$aliases)) { | 
| 521: | $trimmed_trace = array(); | 
| 522: | } | 
| 523: |  | 
| 524: | $trimmed_trace[] = $frame; | 
| 525: | } | 
| 526: |  | 
| 527: | $output = $kintstance->dumpAll( | 
| 528: | array($trimmed_trace), | 
| 529: | array(BasicObject::blank('Kint\\Kint::trace()', 'debug_backtrace(true)')) | 
| 530: | ); | 
| 531: |  | 
| 532: | if (self::$return || \in_array('@', $call_info['modifiers'], true)) { | 
| 533: | return $output; | 
| 534: | } | 
| 535: |  | 
| 536: | echo $output; | 
| 537: |  | 
| 538: | if (\in_array('-', $call_info['modifiers'], true)) { | 
| 539: | \flush(); | 
| 540: | } | 
| 541: |  | 
| 542: | return 0; | 
| 543: | } | 
| 544: |  | 
| 545: |  | 
| 546: |  | 
| 547: |  | 
| 548: |  | 
| 549: |  | 
| 550: |  | 
| 551: |  | 
| 552: | public static function dump() | 
| 553: | { | 
| 554: | if (!self::$enabled_mode) { | 
| 555: | return 0; | 
| 556: | } | 
| 557: |  | 
| 558: | Utils::normalizeAliases(self::$aliases); | 
| 559: |  | 
| 560: | $args = \func_get_args(); | 
| 561: |  | 
| 562: | $call_info = self::getCallInfo(self::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), \count($args)); | 
| 563: |  | 
| 564: | $statics = self::getStatics(); | 
| 565: |  | 
| 566: | if (\in_array('~', $call_info['modifiers'], true)) { | 
| 567: | $statics['enabled_mode'] = self::MODE_TEXT; | 
| 568: | } | 
| 569: |  | 
| 570: | $kintstance = self::createFromStatics($statics); | 
| 571: | if (!$kintstance) { | 
| 572: |  | 
| 573: | return 0; | 
| 574: | } | 
| 575: |  | 
| 576: | if (\in_array('-', $call_info['modifiers'], true)) { | 
| 577: | while (\ob_get_level()) { | 
| 578: | \ob_end_clean(); | 
| 579: | } | 
| 580: | } | 
| 581: |  | 
| 582: | $kintstance->setStatesFromStatics($statics); | 
| 583: | $kintstance->setStatesFromCallInfo($call_info); | 
| 584: |  | 
| 585: |  | 
| 586: | if ($args === array(1) && (!isset($call_info['params'][0]['name']) || '1' === $call_info['params'][0]['name'])) { | 
| 587: | $args = \debug_backtrace(true); | 
| 588: | $trace = array(); | 
| 589: |  | 
| 590: | foreach ($args as $index => $frame) { | 
| 591: | if (Utils::traceFrameIsListed($frame, self::$aliases)) { | 
| 592: | $trace = array(); | 
| 593: | } | 
| 594: |  | 
| 595: | $trace[] = $frame; | 
| 596: | } | 
| 597: |  | 
| 598: | if (isset($call_info['callee']['function'])) { | 
| 599: | $tracename = $call_info['callee']['function'].'(1)'; | 
| 600: | if (isset($call_info['callee']['class'], $call_info['callee']['type'])) { | 
| 601: | $tracename = $call_info['callee']['class'].$call_info['callee']['type'].$tracename; | 
| 602: | } | 
| 603: | } else { | 
| 604: | $tracename = 'Kint\\Kint::dump(1)'; | 
| 605: | } | 
| 606: |  | 
| 607: | $tracebase = BasicObject::blank($tracename, 'debug_backtrace(true)'); | 
| 608: |  | 
| 609: | $output = $kintstance->dumpAll(array($trace), array($tracebase)); | 
| 610: | } else { | 
| 611: | $bases = self::getBasesFromParamInfo( | 
| 612: | isset($call_info['params']) ? $call_info['params'] : array(), | 
| 613: | \count($args) | 
| 614: | ); | 
| 615: | $output = $kintstance->dumpAll($args, $bases); | 
| 616: | } | 
| 617: |  | 
| 618: | if (self::$return || \in_array('@', $call_info['modifiers'], true)) { | 
| 619: | return $output; | 
| 620: | } | 
| 621: |  | 
| 622: | echo $output; | 
| 623: |  | 
| 624: | if (\in_array('-', $call_info['modifiers'], true)) { | 
| 625: | \flush(); | 
| 626: | } | 
| 627: |  | 
| 628: | return 0; | 
| 629: | } | 
| 630: |  | 
| 631: |  | 
| 632: |  | 
| 633: |  | 
| 634: |  | 
| 635: |  | 
| 636: |  | 
| 637: |  | 
| 638: |  | 
| 639: | public static function shortenPath($file) | 
| 640: | { | 
| 641: | $file = \array_values(\array_filter(\explode('/', \str_replace('\\', '/', $file)), 'strlen')); | 
| 642: |  | 
| 643: | $longest_match = 0; | 
| 644: | $match = '/'; | 
| 645: |  | 
| 646: | foreach (self::$app_root_dirs as $path => $alias) { | 
| 647: | if (empty($path)) { | 
| 648: | continue; | 
| 649: | } | 
| 650: |  | 
| 651: | $path = \array_values(\array_filter(\explode('/', \str_replace('\\', '/', $path)), 'strlen')); | 
| 652: |  | 
| 653: | if (\array_slice($file, 0, \count($path)) === $path && \count($path) > $longest_match) { | 
| 654: | $longest_match = \count($path); | 
| 655: | $match = $alias; | 
| 656: | } | 
| 657: | } | 
| 658: |  | 
| 659: | if ($longest_match) { | 
| 660: | $file = \array_merge(array($match), \array_slice($file, $longest_match)); | 
| 661: |  | 
| 662: | return \implode('/', $file); | 
| 663: | } | 
| 664: |  | 
| 665: |  | 
| 666: | $kint = \array_values(\array_filter(\explode('/', \str_replace('\\', '/', KINT_DIR)), 'strlen')); | 
| 667: |  | 
| 668: | foreach ($file as $i => $part) { | 
| 669: | if (!isset($kint[$i]) || $kint[$i] !== $part) { | 
| 670: | return ($i ? '.../' : '/').\implode('/', \array_slice($file, $i)); | 
| 671: | } | 
| 672: | } | 
| 673: |  | 
| 674: | return '/'.\implode('/', $file); | 
| 675: | } | 
| 676: |  | 
| 677: | public static function getIdeLink($file, $line) | 
| 678: | { | 
| 679: | return \str_replace(array('%f', '%l'), array($file, $line), self::$file_link_format); | 
| 680: | } | 
| 681: |  | 
| 682: |  | 
| 683: |  | 
| 684: |  | 
| 685: |  | 
| 686: |  | 
| 687: |  | 
| 688: |  | 
| 689: |  | 
| 690: | protected static function getSingleCall(array $frame, $argc) | 
| 691: | { | 
| 692: | if (!isset($frame['file'], $frame['line'], $frame['function']) || !\is_readable($frame['file'])) { | 
| 693: | return null; | 
| 694: | } | 
| 695: |  | 
| 696: | if (empty($frame['class'])) { | 
| 697: | $callfunc = $frame['function']; | 
| 698: | } else { | 
| 699: | $callfunc = array($frame['class'], $frame['function']); | 
| 700: | } | 
| 701: |  | 
| 702: | $calls = CallFinder::getFunctionCalls( | 
| 703: | \file_get_contents($frame['file']), | 
| 704: | $frame['line'], | 
| 705: | $callfunc | 
| 706: | ); | 
| 707: |  | 
| 708: | $return = null; | 
| 709: |  | 
| 710: | foreach ($calls as $call) { | 
| 711: | $is_unpack = false; | 
| 712: |  | 
| 713: |  | 
| 714: | if (KINT_PHP56) { | 
| 715: | foreach ($call['parameters'] as $i => &$param) { | 
| 716: | if (0 === \strpos($param['name'], '...')) { | 
| 717: | if ($i < $argc && $i === \count($call['parameters']) - 1) { | 
| 718: | for ($j = 1; $j + $i < $argc; ++$j) { | 
| 719: | $call['parameters'][] = array( | 
| 720: | 'name' => 'array_values('.\substr($param['name'], 3).')['.$j.']', | 
| 721: | 'path' => 'array_values('.\substr($param['path'], 3).')['.$j.']', | 
| 722: | 'expression' => false, | 
| 723: | ); | 
| 724: | } | 
| 725: |  | 
| 726: | $param['name'] = 'reset('.\substr($param['name'], 3).')'; | 
| 727: | $param['path'] = 'reset('.\substr($param['path'], 3).')'; | 
| 728: | $param['expression'] = false; | 
| 729: | } else { | 
| 730: | $call['parameters'] = \array_slice($call['parameters'], 0, $i); | 
| 731: | } | 
| 732: |  | 
| 733: | $is_unpack = true; | 
| 734: | break; | 
| 735: | } | 
| 736: |  | 
| 737: | if ($i >= $argc) { | 
| 738: | continue 2; | 
| 739: | } | 
| 740: | } | 
| 741: | } | 
| 742: |  | 
| 743: | if ($is_unpack || \count($call['parameters']) === $argc) { | 
| 744: | if (null === $return) { | 
| 745: | $return = $call; | 
| 746: | } else { | 
| 747: |  | 
| 748: |  | 
| 749: | return null; | 
| 750: | } | 
| 751: | } | 
| 752: | } | 
| 753: |  | 
| 754: | return $return; | 
| 755: | } | 
| 756: | } | 
| 757: |  |