/** * @param $variable * * @return array|bool */ public function parse(&$variable) { if (!$variable instanceof \Closure) { return false; } $this->name = 'Closure'; $reflection = new \ReflectionFunction($variable); $ret = array('Parameters' => array()); $val = $reflection->getParameters(); if ($val) { foreach ($val as $parameter) { // todo http://php.net/manual/en/class.reflectionparameter.php $ret['Parameters'][] = $parameter->name; } } $val = $reflection->getStaticVariables(); if ($val) { $ret['Uses'] = $val; } if (method_exists($reflection, 'getClousureThis') && ($val = $reflection->getClosureThis())) { $ret['Uses']['$this'] = $val; } $val = $reflection->getFileName(); if ($val) { $this->value = Kint::shortenPath($val) . ':' . $reflection->getStartLine(); } return $ret; }
/** * @param string $file * @param int $line * * @return string */ private static function _ideLink($file, $line) { $shortenedPath = Kint::shortenPath($file); if (!Kint::$fileLinkFormat) { return $shortenedPath . ':' . $line; } $ideLink = Kint::getIdeLink($file, $line); $class = strpos($ideLink, 'http://') === 0 ? 'class="kint-ide-link" ' : ''; return "<a {$class}href=\"{$ideLink}\">{$shortenedPath}:{$line}</a>"; }
/** * the only public entry point to return a parsed representation of a variable * * @static * * @param mixed $variable * @param null|string $name * * @return KintParser */ public static final function factory(&$variable, $name = null) { # save internal data to revert after dumping to properly handle recursions etc $revert = array('level' => self::$_level, 'objects' => self::$_objects); self::$_level++; $varData = new KintVariableData(); $varData->name = $name; # first parse the variable based on its type $varType = gettype($variable); if ($varType === 'unknown type') { $varType = 'unknown'; # PHP 5.4 inconsistency } $methodName = '_parse_' . $varType; # objects can be presented in a different way altogether, INSTEAD, not ALONGSIDE the generic parser if ($varType === 'object') { foreach (self::$_objectParsers as $parserClass) { $className = 'kint\\parsers\\objects\\Kint_Objects_' . $parserClass; /** @var $object KintObject */ $object = new $className(); if (($alternativeTabs = $object->parse($variable)) !== false) { self::$_skipAlternatives = true; $alternativeDisplay = new KintVariableData(); $alternativeDisplay->type = $object->name; $alternativeDisplay->value = $object->value; $alternativeDisplay->name = $name; foreach ($alternativeTabs as $nameInner => $values) { $alternative = self::factory($values); $alternative->type = $nameInner; if (Kint::enabled() === Kint::MODE_RICH) { empty($alternative->value) and $alternative->value = $alternative->extendedValue; $alternativeDisplay->_alternatives[] = $alternative; } else { $alternativeDisplay->extendedValue[] = $alternative; } } self::$_skipAlternatives = false; self::$_level = $revert['level']; self::$_objects = $revert['objects']; return $alternativeDisplay; } } } # base type parser returning false means "stop processing further": e.g. recursion if (self::$methodName($variable, $varData) === false) { self::$_level--; return $varData; } if (!self::$_skipAlternatives && Kint::enabled() === Kint::MODE_RICH) { # if an alternative returns something that can be represented in an alternative way, don't :) self::$_skipAlternatives = true; # now check whether the variable can be represented in a different way foreach (self::$_customDataTypes as $parserClass) { $className = 'kint\\parsers\\custom\\Kint_Parsers_' . $parserClass; /** @var $parser KintParser */ $parser = new $className(); $parser->name = $name; # the parser may overwrite the name value, so set it first if ($parser->_parse($variable) !== false) { $varData->_alternatives[] = $parser; } } # if alternatives exist, push extendedValue to their front and display it as one of alternatives if (!empty($varData->_alternatives) && isset($varData->extendedValue)) { $_ = new KintVariableData(); $_->value = $varData->extendedValue; $_->type = 'contents'; $_->size = null; array_unshift($varData->_alternatives, $_); $varData->extendedValue = null; } self::$_skipAlternatives = false; } self::$_level = $revert['level']; self::$_objects = $revert['objects']; if (strlen($varData->name) > 80) { $varData->name = self::_substr($varData->name, 0, 37) . '...' . self::_substr($varData->name, -38, null); } return $varData; }
/** * @return string */ public static function wrapStart() { if (Kint::enabled() === Kint::MODE_PLAIN) { return '<pre class="-kint">'; } return ''; }
/** * @param mixed $variable * * @return bool */ protected function _parse(&$variable) { if (!is_object($variable)) { return false; } $className = get_class($variable); # assuming class definition will not change inside one request if (!isset(self::$cache[$className])) { $reflection = new \ReflectionClass($variable); $public = $private = $protected = array(); // Class methods foreach ($reflection->getMethods() as $method) { $params = array(); // Access type $access = implode(' ', \Reflection::getModifierNames($method->getModifiers())); // Method parameters foreach ($method->getParameters() as $param) { $paramString = ''; if ($param->isArray()) { $paramString .= 'array '; } else { try { $paramClassName = $param->getClass(); if ($paramClassName) { $paramString .= $paramClassName->name . ' '; } } catch (\ReflectionException $e) { preg_match('/\\[\\s\\<\\w+?>\\s([\\w]+)/', (string) $param, $matches); $paramClassName = isset($matches[1]) ? $matches[1] : ''; $paramString .= ' UNDEFINED CLASS (' . $paramClassName . ') '; } } $paramString .= ($param->isPassedByReference() ? '&' : '') . '$' . $param->getName(); if ($param->isDefaultValueAvailable()) { if (is_array($param->getDefaultValue())) { $arrayValues = array(); foreach ($param->getDefaultValue() as $key => $value) { $arrayValues[] = $key . ' => ' . $value; } $defaultValue = 'array(' . implode(', ', $arrayValues) . ')'; } elseif ($param->getDefaultValue() === null) { $defaultValue = 'NULL'; } elseif ($param->getDefaultValue() === false) { $defaultValue = 'false'; } elseif ($param->getDefaultValue() === true) { $defaultValue = 'true'; } elseif ($param->getDefaultValue() === '') { $defaultValue = '""'; } else { $defaultValue = $param->getDefaultValue(); } $paramString .= ' = ' . $defaultValue; } $params[] = $paramString; } $output = new KintVariableData(); // Simple DocBlock parser, look for @return $docBlock = $method->getDocComment(); if ($docBlock) { $matches = array(); if (preg_match_all('/@(\\w+)\\s+(.*)\\r?\\n/m', $docBlock, $matches)) { $lines = array_combine($matches[1], $matches[2]); if (isset($lines['return'])) { $output->operator = '->'; # since we're outputting code, assumption that the string is utf8 is most likely correct # and saves resources $output->type = self::escape($lines['return'], 'UTF-8'); } } } $output->name = ($method->returnsReference() ? '&' : '') . $method->getName() . '(' . implode(', ', $params) . ')'; $output->access = $access; if (is_string($docBlock)) { $lines = array(); foreach (explode("\n", $docBlock) as $line) { $line = trim($line); if (in_array($line, array('/**', '/*', '*/'), true)) { continue; } elseif (strpos($line, '*') === 0) { $line = trim(substr($line, 1)); } $lines[] = self::escape($line, 'UTF-8'); } $output->extendedValue = implode("\n", $lines) . "\n\n"; } $declaringClass = $method->getDeclaringClass(); $declaringClassName = $declaringClass->getName(); if ($declaringClassName !== $className) { /** @noinspection PhpToStringImplementationInspection */ $output->extendedValue .= "<small>Inherited from <i>{$declaringClassName}</i></small>\n"; } $fileName = Kint::shortenPath($method->getFileName()) . ':' . $method->getStartLine(); /** @noinspection PhpToStringImplementationInspection */ $output->extendedValue .= "<small>Defined in {$fileName}</small>"; $sortName = $access . $method->getName(); if ($method->isPrivate()) { $private[$sortName] = $output; } elseif ($method->isProtected()) { $protected[$sortName] = $output; } else { $public[$sortName] = $output; } } if (!$private && !$protected && !$public) { self::$cache[$className] = false; } ksort($public); ksort($protected); ksort($private); /** @noinspection AdditionOperationOnArraysInspection */ self::$cache[$className] = $public + $protected + $private; } if (count(self::$cache[$className]) === 0) { return false; } $this->value = self::$cache[$className]; $this->type = 'Available methods'; $this->size = count(self::$cache[$className]); return true; }