├── LICENSE ├── README.md ├── composer.json ├── init.php ├── init_helpers.php ├── resources └── compiled │ ├── aante-dark.css │ ├── aante-light.css │ ├── main.js │ ├── original.css │ ├── plain.css │ ├── solarized-dark.css │ └── solarized.css └── src ├── CallFinder.php ├── FacadeInterface.php ├── Kint.php ├── Parser ├── AbstractPlugin.php ├── ArrayLimitPlugin.php ├── ArrayObjectPlugin.php ├── Base64Plugin.php ├── BinaryPlugin.php ├── BlacklistPlugin.php ├── ClassHooksPlugin.php ├── ClassMethodsPlugin.php ├── ClassStaticsPlugin.php ├── ClassStringsPlugin.php ├── ClosurePlugin.php ├── ColorPlugin.php ├── ConstructablePluginInterface.php ├── DateTimePlugin.php ├── DomPlugin.php ├── EnumPlugin.php ├── FsPathPlugin.php ├── HtmlPlugin.php ├── IteratorPlugin.php ├── JsonPlugin.php ├── MicrotimePlugin.php ├── MysqliPlugin.php ├── Parser.php ├── PluginBeginInterface.php ├── PluginCompleteInterface.php ├── PluginInterface.php ├── ProfilePlugin.php ├── ProxyPlugin.php ├── SerializePlugin.php ├── SimpleXMLElementPlugin.php ├── SplFileInfoPlugin.php ├── StreamPlugin.php ├── TablePlugin.php ├── ThrowablePlugin.php ├── TimestampPlugin.php ├── ToStringPlugin.php ├── TracePlugin.php └── XmlPlugin.php ├── Renderer ├── AbstractRenderer.php ├── AssetRendererTrait.php ├── CliRenderer.php ├── ConstructableRendererInterface.php ├── PlainRenderer.php ├── RendererInterface.php ├── Rich │ ├── AbstractPlugin.php │ ├── BinaryPlugin.php │ ├── CallableDefinitionPlugin.php │ ├── CallablePlugin.php │ ├── ColorPlugin.php │ ├── LockPlugin.php │ ├── MicrotimePlugin.php │ ├── PluginInterface.php │ ├── ProfilePlugin.php │ ├── SourcePlugin.php │ ├── TabPluginInterface.php │ ├── TablePlugin.php │ ├── TraceFramePlugin.php │ └── ValuePluginInterface.php ├── RichRenderer.php ├── Text │ ├── AbstractPlugin.php │ ├── LockPlugin.php │ ├── MicrotimePlugin.php │ ├── PluginInterface.php │ ├── SplFileInfoPlugin.php │ └── TracePlugin.php └── TextRenderer.php ├── Utils.php └── Value ├── AbstractValue.php ├── ArrayValue.php ├── ClosedResourceValue.php ├── ClosureValue.php ├── ColorValue.php ├── Context ├── ArrayContext.php ├── BaseContext.php ├── ClassConstContext.php ├── ClassDeclaredContext.php ├── ClassOwnedContext.php ├── ContextInterface.php ├── DoubleAccessMemberContext.php ├── MethodContext.php ├── PropertyContext.php └── StaticPropertyContext.php ├── DateTimeValue.php ├── DeclaredCallableBag.php ├── DomNodeListValue.php ├── DomNodeValue.php ├── EnumValue.php ├── FixedWidthValue.php ├── FunctionValue.php ├── InstanceValue.php ├── MethodValue.php ├── MicrotimeValue.php ├── ParameterBag.php ├── ParameterHoldingTrait.php ├── Representation ├── AbstractRepresentation.php ├── BinaryRepresentation.php ├── CallableDefinitionRepresentation.php ├── ColorRepresentation.php ├── ContainerRepresentation.php ├── MicrotimeRepresentation.php ├── ProfileRepresentation.php ├── RepresentationInterface.php ├── SourceRepresentation.php ├── SplFileInfoRepresentation.php ├── StringRepresentation.php ├── TableRepresentation.php └── ValueRepresentation.php ├── ResourceValue.php ├── SimpleXMLElementValue.php ├── SplFileInfoValue.php ├── StreamValue.php ├── StringValue.php ├── ThrowableValue.php ├── TraceFrameValue.php ├── TraceValue.php ├── UninitializedValue.php ├── UnknownValue.php └── VirtualValue.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kint - Advanced PHP dumper 2 | 3 | ![Screenshot](https://kint-php.github.io/kint/images/intro.png) 4 | 5 | ## What am I looking at? 6 | 7 | Kint is a dumper in the vein of **[var_dump()](https://www.php.net/function.var_dump)**, with keyboard controls, search, access path provision, and automatic data parsing. 8 | 9 | In other words, when you dump a JSON string Kint will let you unfold and search the JSON structure and even provide you the code you need to access specific fields. 10 | 11 | ## Installation 12 | 13 | ```bash 14 | composer require kint-php/kint --dev 15 | ``` 16 | 17 | ### Without composer 18 | 19 | [Download the file](https://raw.githubusercontent.com/kint-php/kint/master/build/kint.phar) and simply 20 | ```php 21 | require 'kint.phar'; 22 | ``` 23 | 24 | ## Usage 25 | 26 | ```php 27 | =7.4" 20 | }, 21 | "require-dev": { 22 | "friendsofphp/php-cs-fixer": "^3", 23 | "phpunit/phpunit": "^9", 24 | "symfony/finder": ">=7", 25 | "seld/phar-utils": "^1", 26 | "vimeo/psalm": "^6" 27 | }, 28 | "autoload": { 29 | "files": ["init.php"], 30 | "psr-4": { 31 | "Kint\\": "src/" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Kint\\Test\\": "tests/" 37 | } 38 | }, 39 | "config": { 40 | "platform": { 41 | "php": "8.3" 42 | } 43 | }, 44 | "scripts": { 45 | "clean": [ 46 | "rm -rf resources/compiled/", 47 | "rm -rf build/" 48 | ], 49 | "format": [ 50 | "@format:php", 51 | "@format:js", 52 | "@format:sass" 53 | ], 54 | "format:php": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix", 55 | "format:js": "npm run format:js", 56 | "format:sass": "npm run format:sass", 57 | "build": [ 58 | "@build:sass", 59 | "@build:js", 60 | "@build:php" 61 | ], 62 | "build:sass": "npm run build:sass", 63 | "build:js": "npm run build:js", 64 | "build:php": "php ./build.php", 65 | "analyze": [ 66 | "@analyze:php", 67 | "@analyze:js" 68 | ], 69 | "analyze:php": "psalm --no-cache", 70 | "analyze:js": "npm run analyze:js" 71 | }, 72 | "suggest": { 73 | "kint-php/kint-helpers": "Provides extra helper functions", 74 | "kint-php/kint-twig": "Provides d() and s() functions in twig templates" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /init.php: -------------------------------------------------------------------------------- 1 | = 0); 43 | \define('KINT_PHP81', \version_compare(PHP_VERSION, '8.1') >= 0); 44 | \define('KINT_PHP82', \version_compare(PHP_VERSION, '8.2') >= 0); 45 | \define('KINT_PHP83', \version_compare(PHP_VERSION, '8.3') >= 0); 46 | \define('KINT_PHP84', \version_compare(PHP_VERSION, '8.4') >= 0); 47 | \define('KINT_PHP85', \version_compare(PHP_VERSION, '8.5') >= 0); 48 | 49 | // Dynamic default settings 50 | if (\strlen((string) \ini_get('xdebug.file_link_format')) > 0) { 51 | /** @psalm-var non-empty-string ini_get('xdebug.file_link_format') */ 52 | AbstractRenderer::$file_link_format = \ini_get('xdebug.file_link_format'); 53 | } 54 | if (isset($_SERVER['DOCUMENT_ROOT']) && false === \strpos($_SERVER['DOCUMENT_ROOT'], "\0")) { 55 | Utils::$path_aliases = [ 56 | $_SERVER['DOCUMENT_ROOT'] => '', 57 | ]; 58 | 59 | // Suppressed for unreadable document roots (related to open_basedir) 60 | if (false !== @\realpath($_SERVER['DOCUMENT_ROOT'])) { 61 | /** @psalm-suppress InvalidPropertyAssignmentValue */ 62 | Utils::$path_aliases[\realpath($_SERVER['DOCUMENT_ROOT'])] = ''; 63 | } 64 | } 65 | 66 | Utils::composerSkipFlags(); 67 | 68 | if ((!\defined('KINT_SKIP_FACADE') || !KINT_SKIP_FACADE) && !\class_exists('Kint')) { 69 | \class_alias(Kint::class, 'Kint'); 70 | } 71 | 72 | if (!\defined('KINT_SKIP_HELPERS') || !KINT_SKIP_HELPERS) { 73 | require_once __DIR__.'/init_helpers.php'; 74 | } 75 | -------------------------------------------------------------------------------- /init_helpers.php: -------------------------------------------------------------------------------- 1 | parser = $parser; 37 | } 38 | 39 | public function setParser(Parser $p): void 40 | { 41 | $this->parser = $p; 42 | } 43 | 44 | protected function getParser(): Parser 45 | { 46 | return $this->parser; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Parser/ArrayObjectPlugin.php: -------------------------------------------------------------------------------- 1 | getFlags(); 53 | 54 | if (ArrayObject::STD_PROP_LIST === $flags) { 55 | return null; 56 | } 57 | 58 | $parser = $this->getParser(); 59 | 60 | $var->setFlags(ArrayObject::STD_PROP_LIST); 61 | 62 | $v = $parser->parse($var, $c); 63 | 64 | $var->setFlags($flags); 65 | 66 | return $v; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Parser/Base64Plugin.php: -------------------------------------------------------------------------------- 1 | getContext(); 78 | 79 | $base = new BaseContext('base64_decode('.$c->getName().')'); 80 | $base->depth = $c->getDepth() + 1; 81 | 82 | if (null !== ($ap = $c->getAccessPath())) { 83 | $base->access_path = 'base64_decode('.$ap.')'; 84 | } 85 | 86 | $data = $this->getParser()->parse($data, $base); 87 | $data->flags |= AbstractValue::FLAG_GENERATED; 88 | 89 | if (!$data instanceof StringValue || false === $data->getEncoding()) { 90 | return $v; 91 | } 92 | 93 | $r = new ValueRepresentation('Base64', $data); 94 | 95 | if (\strlen($var) > self::$min_length_soft) { 96 | $v->addRepresentation($r, 0); 97 | } else { 98 | $v->addRepresentation($r); 99 | } 100 | 101 | return $v; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Parser/BinaryPlugin.php: -------------------------------------------------------------------------------- 1 | getEncoding()) { 49 | $v->addRepresentation(new BinaryRepresentation($v->getValue(), true), 0); 50 | } 51 | 52 | return $v; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Parser/BlacklistPlugin.php: -------------------------------------------------------------------------------- 1 | blacklistValue($var, $c); 70 | } 71 | } 72 | 73 | if ($c->getDepth() <= 0) { 74 | return null; 75 | } 76 | 77 | foreach (self::$shallow_blacklist as $class) { 78 | if ($var instanceof $class) { 79 | return $this->blacklistValue($var, $c); 80 | } 81 | } 82 | 83 | return null; 84 | } 85 | 86 | /** 87 | * @param object &$var 88 | */ 89 | protected function blacklistValue(&$var, ContextInterface $c): InstanceValue 90 | { 91 | $object = new InstanceValue($c, \get_class($var), \spl_object_hash($var), \spl_object_id($var)); 92 | $object->flags |= AbstractValue::FLAG_BLACKLIST; 93 | 94 | return $object; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Parser/ClassStringsPlugin.php: -------------------------------------------------------------------------------- 1 | methods_plugin = new ClassMethodsPlugin($parser); 47 | $this->statics_plugin = new ClassStaticsPlugin($parser); 48 | } 49 | 50 | public function setParser(Parser $p): void 51 | { 52 | parent::setParser($p); 53 | 54 | $this->methods_plugin->setParser($p); 55 | $this->statics_plugin->setParser($p); 56 | } 57 | 58 | public function getTypes(): array 59 | { 60 | return ['string']; 61 | } 62 | 63 | public function getTriggers(): int 64 | { 65 | return Parser::TRIGGER_SUCCESS; 66 | } 67 | 68 | public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue 69 | { 70 | $c = $v->getContext(); 71 | 72 | if ($c->getDepth() > 0) { 73 | return $v; 74 | } 75 | 76 | if (!\class_exists($var, true)) { 77 | return $v; 78 | } 79 | 80 | if (\in_array($var, self::$blacklist, true)) { 81 | return $v; 82 | } 83 | 84 | $r = new ReflectionClass($var); 85 | 86 | $fakeC = new BaseContext($c->getName()); 87 | $fakeC->access_path = null; 88 | $fakeV = new InstanceValue($fakeC, $r->getName(), 'badhash', -1); 89 | $fakeVar = null; 90 | 91 | $fakeV = $this->methods_plugin->parseComplete($fakeVar, $fakeV, Parser::TRIGGER_SUCCESS); 92 | $fakeV = $this->statics_plugin->parseComplete($fakeVar, $fakeV, Parser::TRIGGER_SUCCESS); 93 | 94 | foreach (['methods', 'static_methods', 'statics', 'constants'] as $rep) { 95 | if ($rep = $fakeV->getRepresentation($rep)) { 96 | $v->addRepresentation($rep); 97 | } 98 | } 99 | 100 | return $v; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Parser/ClosurePlugin.php: -------------------------------------------------------------------------------- 1 | getContext(); 57 | 58 | $object = new ClosureValue($c, $var); 59 | $object->flags = $v->flags; 60 | $object->appendRepresentations($v->getRepresentations()); 61 | 62 | $object->removeRepresentation('properties'); 63 | 64 | $closure = new ReflectionFunction($var); 65 | 66 | $statics = []; 67 | 68 | if ($v = $closure->getClosureThis()) { 69 | $statics = ['this' => $v]; 70 | } 71 | 72 | $statics = $statics + $closure->getStaticVariables(); 73 | 74 | $cdepth = $c->getDepth(); 75 | 76 | if (\count($statics)) { 77 | $statics_parsed = []; 78 | 79 | $parser = $this->getParser(); 80 | 81 | foreach ($statics as $name => $_) { 82 | $base = new BaseContext('$'.$name); 83 | $base->depth = $cdepth + 1; 84 | $base->reference = null !== ReflectionReference::fromArrayElement($statics, $name); 85 | $statics_parsed[$name] = $parser->parse($statics[$name], $base); 86 | } 87 | 88 | $object->addRepresentation(new ContainerRepresentation('Uses', $statics_parsed), 0); 89 | } 90 | 91 | return $object; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Parser/ColorPlugin.php: -------------------------------------------------------------------------------- 1 | 32) { 51 | return $v; 52 | } 53 | 54 | if (!$v instanceof StringValue) { 55 | return $v; 56 | } 57 | 58 | $trimmed = \strtolower(\trim($var)); 59 | 60 | if (!isset(ColorRepresentation::$color_map[$trimmed]) && !\preg_match('/^(?:(?:rgb|hsl)[^\\)]{6,}\\)|#[0-9a-fA-F]{3,8})$/', $trimmed)) { 61 | return $v; 62 | } 63 | 64 | try { 65 | $rep = new ColorRepresentation($var); 66 | } catch (InvalidArgumentException $e) { 67 | return $v; 68 | } 69 | 70 | $out = new ColorValue($v->getContext(), $v->getValue(), $v->getEncoding()); 71 | $out->flags = $v->flags; 72 | $out->appendRepresentations($v->getRepresentations()); 73 | $out->removeRepresentation('contents'); 74 | $out->addRepresentation($rep, 0); 75 | 76 | return $out; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Parser/ConstructablePluginInterface.php: -------------------------------------------------------------------------------- 1 | getContext(), $var); 56 | } catch (Error $e) { 57 | // Only happens if someone makes a DateTimeInterface with a private __clone 58 | return $v; 59 | } 60 | 61 | $dtv->setChildren($v->getChildren()); 62 | $dtv->flags = $v->flags; 63 | $dtv->appendRepresentations($v->getRepresentations()); 64 | 65 | return $dtv; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Parser/EnumPlugin.php: -------------------------------------------------------------------------------- 1 | getContext(); 61 | $class = \get_class($var); 62 | 63 | if (!isset($this->cache[$class])) { 64 | $contents = []; 65 | 66 | foreach ($var->cases() as $case) { 67 | $base = new BaseContext($case->name); 68 | $base->access_path = '\\'.$class.'::'.$case->name; 69 | $base->depth = $c->getDepth() + 1; 70 | $contents[] = new EnumValue($base, $case); 71 | } 72 | 73 | /** @psalm-var non-empty-array $contents */ 74 | $this->cache[$class] = new ContainerRepresentation('Enum values', $contents, 'enum'); 75 | } 76 | 77 | $object = new EnumValue($c, $var); 78 | $object->flags = $v->flags; 79 | $object->appendRepresentations($v->getRepresentations()); 80 | $object->addRepresentation($this->cache[$class], 0); 81 | 82 | return $object; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Parser/FsPathPlugin.php: -------------------------------------------------------------------------------- 1 | 2048) { 52 | return $v; 53 | } 54 | 55 | if (!\preg_match('/[\\/\\'.DIRECTORY_SEPARATOR.']/', $var)) { 56 | return $v; 57 | } 58 | 59 | if (\preg_match('/[?<>"*|]/', $var)) { 60 | return $v; 61 | } 62 | 63 | try { 64 | if (!@\file_exists($var)) { 65 | return $v; 66 | } 67 | } catch (TypeError $e) {// @codeCoverageIgnore 68 | // Only possible in PHP 7 69 | return $v; // @codeCoverageIgnore 70 | } 71 | 72 | if (\in_array($var, self::$blacklist, true)) { 73 | return $v; 74 | } 75 | 76 | $v->addRepresentation(new SplFileInfoRepresentation(new SplFileInfo($var)), 0); 77 | 78 | return $v; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Parser/HtmlPlugin.php: -------------------------------------------------------------------------------- 1 | ' !== \strtolower((string) \substr($var, 0, 15))) { 56 | return $v; 57 | } 58 | 59 | try { 60 | $html = HTMLDocument::createFromString($var, LIBXML_NOERROR); 61 | } catch (DOMException $e) { // @codeCoverageIgnore 62 | return $v; // @codeCoverageIgnore 63 | } 64 | 65 | $c = $v->getContext(); 66 | 67 | $base = new BaseContext('childNodes'); 68 | $base->depth = $c->getDepth(); 69 | 70 | if (null !== ($ap = $c->getAccessPath())) { 71 | $base->access_path = '\\Dom\\HTMLDocument::createFromString('.$ap.')->childNodes'; 72 | } 73 | 74 | $out = $this->getParser()->parse($html->childNodes, $base); 75 | $iter = $out->getRepresentation('iterator'); 76 | 77 | if ($out->flags & AbstractValue::FLAG_DEPTH_LIMIT) { 78 | $out->flags |= AbstractValue::FLAG_GENERATED; 79 | $v->addRepresentation(new ValueRepresentation('HTML', $out), 0); 80 | } elseif ($iter instanceof ContainerRepresentation) { 81 | $v->addRepresentation(new ContainerRepresentation('HTML', $iter->getContents()), 0); 82 | } 83 | 84 | return $v; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Parser/JsonPlugin.php: -------------------------------------------------------------------------------- 1 | getContext(); 64 | 65 | $base = new BaseContext('JSON Decode'); 66 | $base->depth = $c->getDepth(); 67 | 68 | if (null !== ($ap = $c->getAccessPath())) { 69 | $base->access_path = 'json_decode('.$ap.', true)'; 70 | } 71 | 72 | $json = $this->getParser()->parse($json, $base); 73 | 74 | if ($json instanceof ArrayValue && (~$json->flags & AbstractValue::FLAG_DEPTH_LIMIT) && $contents = $json->getContents()) { 75 | foreach ($contents as $value) { 76 | $value->flags |= AbstractValue::FLAG_GENERATED; 77 | } 78 | $v->addRepresentation(new ContainerRepresentation('Json', $contents), 0); 79 | } else { 80 | $json->flags |= AbstractValue::FLAG_GENERATED; 81 | $v->addRepresentation(new ValueRepresentation('Json', $json), 0); 82 | } 83 | 84 | return $v; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Parser/PluginBeginInterface.php: -------------------------------------------------------------------------------- 1 | types = $types; 54 | $this->triggers = $triggers; 55 | $this->callback = $callback; 56 | } 57 | 58 | public function setParser(Parser $p): void 59 | { 60 | $this->parser = $p; 61 | } 62 | 63 | public function getTypes(): array 64 | { 65 | return $this->types; 66 | } 67 | 68 | public function getTriggers(): int 69 | { 70 | return $this->triggers; 71 | } 72 | 73 | public function parseBegin(&$var, ContextInterface $c): ?AbstractValue 74 | { 75 | return \call_user_func_array($this->callback, [ 76 | &$var, 77 | $c, 78 | Parser::TRIGGER_BEGIN, 79 | $this->parser, 80 | ]); 81 | } 82 | 83 | public function parseComplete(&$var, AbstractValue $v, int $trigger): AbstractValue 84 | { 85 | return \call_user_func_array($this->callback, [ 86 | &$var, 87 | $v, 88 | $trigger, 89 | $this->parser, 90 | ]); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Parser/SplFileInfoPlugin.php: -------------------------------------------------------------------------------- 1 | getContext(), $var); 61 | $out->setChildren($v->getChildren()); 62 | $out->flags = $v->flags; 63 | $out->addRepresentation(new SplFileInfoRepresentation(clone $var)); 64 | $out->appendRepresentations($v->getRepresentations()); 65 | 66 | return $out; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Parser/StreamPlugin.php: -------------------------------------------------------------------------------- 1 | getContext(); 66 | 67 | $parser = $this->getParser(); 68 | $parsed_meta = []; 69 | foreach ($meta as $key => $val) { 70 | $base = new ArrayContext($key); 71 | $base->depth = $c->getDepth() + 1; 72 | 73 | if (null !== ($ap = $c->getAccessPath())) { 74 | $base->access_path = 'stream_get_meta_data('.$ap.')['.\var_export($key, true).']'; 75 | } 76 | 77 | $val = $parser->parse($val, $base); 78 | $val->flags |= AbstractValue::FLAG_GENERATED; 79 | $parsed_meta[] = $val; 80 | } 81 | 82 | $stream = new StreamValue($c, $parsed_meta, $meta['uri'] ?? null); 83 | $stream->flags = $v->flags; 84 | $stream->appendRepresentations($v->getRepresentations()); 85 | 86 | return $stream; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Parser/TablePlugin.php: -------------------------------------------------------------------------------- 1 | self::$max_width) { 76 | return $v; 77 | } 78 | 79 | $keys = \array_keys($elem); 80 | } elseif (\array_keys($elem) !== $keys) { 81 | return $v; 82 | } 83 | } 84 | 85 | $children = $v->getContents(); 86 | 87 | if (!$children) { 88 | return $v; 89 | } 90 | 91 | // Ensure none of the child arrays are recursion or depth limit. We 92 | // don't care if their children are since they are the table cells 93 | foreach ($children as $childarray) { 94 | if (!$childarray instanceof ArrayValue || empty($childarray->getContents())) { 95 | return $v; 96 | } 97 | } 98 | 99 | $v->addRepresentation(new TableRepresentation($children), 0); 100 | 101 | return $v; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Parser/ThrowablePlugin.php: -------------------------------------------------------------------------------- 1 | getContext(), $var); 56 | $throw->setChildren($v->getChildren()); 57 | $throw->flags = $v->flags; 58 | $throw->appendRepresentations($v->getRepresentations()); 59 | 60 | try { 61 | $throw->addRepresentation(new SourceRepresentation($var->getFile(), $var->getLine(), null, true), 0); 62 | } catch (RuntimeException $e) { 63 | } 64 | 65 | return $throw; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Parser/TimestampPlugin.php: -------------------------------------------------------------------------------- 1 | 10) { 73 | return $v; 74 | } 75 | 76 | if (!$v instanceof StringValue && !$v instanceof FixedWidthValue) { 77 | return $v; 78 | } 79 | 80 | if (!$dt = DateTimeImmutable::createFromFormat('U', (string) $var)) { 81 | return $v; 82 | } 83 | 84 | $v->removeRepresentation('contents'); 85 | $v->addRepresentation(new StringRepresentation('Timestamp', $dt->format('c'), null, true)); 86 | 87 | return $v; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Parser/ToStringPlugin.php: -------------------------------------------------------------------------------- 1 | hasMethod('__toString')) { 59 | return $v; 60 | } 61 | 62 | foreach (self::$blacklist as $class) { 63 | if ($var instanceof $class) { 64 | return $v; 65 | } 66 | } 67 | 68 | try { 69 | $string = (string) $var; 70 | } catch (Throwable $t) { 71 | return $v; 72 | } 73 | 74 | $c = $v->getContext(); 75 | 76 | $base = new BaseContext($c->getName()); 77 | $base->depth = $c->getDepth() + 1; 78 | if (null !== ($ap = $c->getAccessPath())) { 79 | $base->access_path = '(string) '.$ap; 80 | } 81 | 82 | $string = $this->getParser()->parse($string, $base); 83 | 84 | $v->addRepresentation(new ValueRepresentation('toString', $string)); 85 | 86 | return $v; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Renderer/AbstractRenderer.php: -------------------------------------------------------------------------------- 1 | render_spl_ids; 51 | } 52 | 53 | public function setCallInfo(array $info): void 54 | { 55 | $this->callee = $info['callee'] ?? null; 56 | $this->trace = $info['trace'] ?? []; 57 | } 58 | 59 | public function setStatics(array $statics): void 60 | { 61 | $this->show_trace = !empty($statics['display_called_from']); 62 | } 63 | 64 | public function filterParserPlugins(array $plugins): array 65 | { 66 | return $plugins; 67 | } 68 | 69 | public function preRender(): string 70 | { 71 | return ''; 72 | } 73 | 74 | public function postRender(): string 75 | { 76 | return ''; 77 | } 78 | 79 | public static function getFileLink(string $file, int $line): ?string 80 | { 81 | if (null === self::$file_link_format) { 82 | return null; 83 | } 84 | 85 | return \str_replace(['%f', '%l'], [$file, $line], self::$file_link_format); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Renderer/AssetRendererTrait.php: -------------------------------------------------------------------------------- 1 | } */ 35 | private static array $assetCache = []; 36 | 37 | /** @psalm-api */ 38 | public static function renderJs(): string 39 | { 40 | if (!isset(self::$assetCache['js'])) { 41 | self::$assetCache['js'] = \file_get_contents(KINT_DIR.'/resources/compiled/main.js'); 42 | } 43 | 44 | return self::$assetCache['js']; 45 | } 46 | 47 | /** @psalm-api */ 48 | public static function renderCss(): ?string 49 | { 50 | if (!isset(self::$theme)) { 51 | return null; 52 | } 53 | 54 | if (!isset(self::$assetCache['css'][self::$theme])) { 55 | if (\file_exists(KINT_DIR.'/resources/compiled/'.self::$theme)) { 56 | self::$assetCache['css'][self::$theme] = \file_get_contents(KINT_DIR.'/resources/compiled/'.self::$theme); 57 | } elseif (\file_exists(self::$theme)) { 58 | self::$assetCache['css'][self::$theme] = \file_get_contents(self::$theme); 59 | } else { 60 | self::$assetCache['css'][self::$theme] = false; 61 | } 62 | } 63 | 64 | if (false === self::$assetCache['css'][self::$theme]) { 65 | return null; 66 | } 67 | 68 | return self::$assetCache['css'][self::$theme]; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Renderer/ConstructableRendererInterface.php: -------------------------------------------------------------------------------- 1 | renderer = $r; 43 | } 44 | 45 | /** 46 | * @param string $content The replacement for the getValueShort contents 47 | */ 48 | public function renderLockedHeader(AbstractValue $v, string $content): string 49 | { 50 | $header = '
'; 51 | 52 | $c = $v->getContext(); 53 | 54 | if (RichRenderer::$access_paths && $c->getDepth() > 0 && null !== ($ap = $c->getAccessPath())) { 55 | $header .= ''; 56 | } 57 | 58 | $header .= ''; 59 | 60 | if ($c instanceof ClassDeclaredContext) { 61 | $header .= ''.$c->getModifiers().' '; 62 | } 63 | 64 | $header .= ''.$this->renderer->escape($v->getDisplayName()).' '; 65 | 66 | if ($c instanceof PropertyContext && null !== ($s = $c->getHooks())) { 67 | $header .= ''.$this->renderer->escape($s).' '; 68 | } 69 | 70 | if (null !== ($s = $c->getOperator())) { 71 | $header .= $this->renderer->escape($s, 'ASCII').' '; 72 | } 73 | 74 | $s = $v->getDisplayType(); 75 | 76 | if (RichRenderer::$escape_types) { 77 | $s = $this->renderer->escape($s); 78 | } 79 | 80 | if ($c->isRef()) { 81 | $s = '&'.$s; 82 | } 83 | 84 | $header .= ''.$s.''; 85 | 86 | if ($v instanceof InstanceValue && $this->renderer->shouldRenderObjectIds()) { 87 | $header .= '#'.$v->getSplObjectId(); 88 | } 89 | 90 | $header .= ' '; 91 | 92 | if (null !== ($s = $v->getDisplaySize())) { 93 | if (RichRenderer::$escape_types) { 94 | $s = $this->renderer->escape($s); 95 | } 96 | $header .= '('.$s.') '; 97 | } 98 | 99 | $header .= $content; 100 | 101 | if (!empty($ap)) { 102 | $header .= '
'.$this->renderer->escape($ap).'
'; 103 | } 104 | 105 | return $header.'
'; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Renderer/Rich/BinaryPlugin.php: -------------------------------------------------------------------------------- 1 | '; 48 | 49 | $lines = \str_split($r->getValue(), self::$line_length); 50 | 51 | foreach ($lines as $index => $line) { 52 | $out .= ((string) \sprintf('%08X', $index * self::$line_length)).":\t"; 53 | 54 | $chunks = \str_split(\str_pad(\bin2hex($line), 2 * self::$line_length, ' '), 2 * self::$chunk_length); 55 | 56 | $out .= \implode(' ', $chunks); 57 | $out .= "\t".\preg_replace('/[^\\x20-\\x7E]/', '.', $line)."\n"; 58 | } 59 | 60 | $out .= ''; 61 | 62 | return $out; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Renderer/Rich/CallableDefinitionPlugin.php: -------------------------------------------------------------------------------- 1 | getContext(); 48 | 49 | if ($c->inherited) { 50 | $docstring[] = 'Inherited from '.$this->renderer->escape($c->owner_class); 51 | } 52 | } 53 | 54 | $docstring[] = 'Defined in '.$this->renderer->escape(Utils::shortenPath($r->getFileName())).':'.$r->getLine(); 55 | 56 | $docstring = ''.\implode("\n", $docstring).''; 57 | 58 | if (null !== ($trimmed = $r->getDocstringTrimmed())) { 59 | $docstring = $this->renderer->escape($trimmed)."\n\n".$docstring; 60 | } 61 | 62 | return '
'.$docstring.'
'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Renderer/Rich/LockPlugin.php: -------------------------------------------------------------------------------- 1 | getHint()) { 37 | case 'blacklist': 38 | return '
'.$this->renderLockedHeader($v, 'Blacklisted').'
'; 39 | case 'recursion': 40 | return '
'.$this->renderLockedHeader($v, 'Recursion').'
'; 41 | case 'depth_limit': 42 | return '
'.$this->renderLockedHeader($v, 'Depth Limit').'
'; 43 | case 'array_limit': 44 | return '
'.$this->renderLockedHeader($v, 'Array Limit').'
'; 45 | } 46 | 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Renderer/Rich/MicrotimePlugin.php: -------------------------------------------------------------------------------- 1 | getDateTime())) { 40 | return null; 41 | } 42 | 43 | $out = $dt->format('Y-m-d H:i:s.u'); 44 | if (null !== ($lap = $r->getLapTime())) { 45 | $out .= '
SINCE LAST CALL: '.\round($lap, 4).'s.'; 46 | } 47 | if (null !== ($total = $r->getTotalTime())) { 48 | $out .= '
SINCE START: '.\round($total, 4).'s.'; 49 | } 50 | if (null !== ($avg = $r->getAverageTime())) { 51 | $out .= '
AVERAGE DURATION: '.\round($avg, 4).'s.'; 52 | } 53 | 54 | $bytes = Utils::getHumanReadableBytes($r->getMemoryUsage()); 55 | $out .= '
MEMORY USAGE: '.$r->getMemoryUsage().' bytes ('.\round($bytes['value'], 3).' '.$bytes['unit'].')'; 56 | $bytes = Utils::getHumanReadableBytes($r->getMemoryUsageReal()); 57 | $out .= ' (real '.\round($bytes['value'], 3).' '.$bytes['unit'].')'; 58 | 59 | $bytes = Utils::getHumanReadableBytes($r->getMemoryPeakUsage()); 60 | $out .= '
PEAK MEMORY USAGE: '.$r->getMemoryPeakUsage().' bytes ('.\round($bytes['value'], 3).' '.$bytes['unit'].')'; 61 | $bytes = Utils::getHumanReadableBytes($r->getMemoryPeakUsageReal()); 62 | $out .= ' (real '.\round($bytes['value'], 3).' '.$bytes['unit'].')'; 63 | 64 | return '
'.$out.'
'; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Renderer/Rich/PluginInterface.php: -------------------------------------------------------------------------------- 1 | '; 43 | 44 | $out .= 'Complexity: '.$r->complexity.PHP_EOL; 45 | if (isset($r->instance_counts)) { 46 | $out .= 'Instance repetitions: '.\var_export($r->instance_counts, true).PHP_EOL; 47 | } 48 | if (isset($r->instance_complexity)) { 49 | $out .= 'Instance complexity: '.\var_export($r->instance_complexity, true).PHP_EOL; 50 | } 51 | 52 | $out .= ''; 53 | 54 | return $out; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Renderer/Rich/SourcePlugin.php: -------------------------------------------------------------------------------- 1 | getSourceLines(); 43 | 44 | // Trim empty lines from the start and end of the source 45 | foreach ($source as $linenum => $line) { 46 | if (\strlen(\trim($line)) || $linenum === $r->getLine()) { 47 | break; 48 | } 49 | 50 | unset($source[$linenum]); 51 | } 52 | 53 | foreach (\array_reverse($source, true) as $linenum => $line) { 54 | if (\strlen(\trim($line)) || $linenum === $r->getLine()) { 55 | break; 56 | } 57 | 58 | unset($source[$linenum]); 59 | } 60 | 61 | $output = ''; 62 | 63 | foreach ($source as $linenum => $line) { 64 | if ($linenum === $r->getLine()) { 65 | $output .= '
'.$this->renderer->escape($line)."\n".'
'; 66 | } else { 67 | $output .= '
'.$this->renderer->escape($line)."\n".'
'; 68 | } 69 | } 70 | 71 | if ($output) { 72 | $data = ''; 73 | if ($r->showFileName()) { 74 | $data = ' data-kint-filename="'.$this->renderer->escape($r->getFileName()).'"'; 75 | } 76 | 77 | return '
'.$output.'
'; 78 | } 79 | 80 | return null; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Renderer/Rich/TabPluginInterface.php: -------------------------------------------------------------------------------- 1 | getFile()) && null !== ($line = $v->getLine())) { 43 | $header = ''.$this->renderer->ideLink($file, $line).' '; 44 | } else { 45 | $header = 'PHP internal call '; 46 | } 47 | 48 | if ($callable = $v->getCallable()) { 49 | if ($callable instanceof MethodValue) { 50 | $function = $callable->getFullyQualifiedDisplayName(); 51 | } else { 52 | $function = $callable->getDisplayName(); 53 | } 54 | 55 | $function = $this->renderer->escape($function); 56 | 57 | if (null !== ($url = $callable->getPhpDocUrl())) { 58 | $function = ''.$function.''; 59 | } 60 | 61 | $header .= $function; 62 | } 63 | 64 | $children = $this->renderer->renderChildren($v); 65 | $header = $this->renderer->renderHeaderWrapper($v->getContext(), (bool) \strlen($children), $header); 66 | 67 | return '
'.$header.$children.'
'; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Renderer/Rich/ValuePluginInterface.php: -------------------------------------------------------------------------------- 1 | renderer = $r; 40 | } 41 | 42 | public function renderLockedHeader(AbstractValue $v, ?string $content = null): string 43 | { 44 | $out = ''; 45 | 46 | if (0 === $v->getContext()->getDepth()) { 47 | $out .= $this->renderer->colorTitle($this->renderer->renderTitle($v)).PHP_EOL; 48 | } 49 | 50 | $out .= $this->renderer->renderHeader($v); 51 | 52 | if (null !== $content) { 53 | $out .= ' '.$this->renderer->colorValue($content); 54 | } 55 | 56 | $out .= PHP_EOL; 57 | 58 | return $out; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Renderer/Text/LockPlugin.php: -------------------------------------------------------------------------------- 1 | getHint()) { 37 | case 'blacklist': 38 | return $this->renderLockedHeader($v, 'BLACKLISTED'); 39 | case 'recursion': 40 | return $this->renderLockedHeader($v, 'RECURSION'); 41 | case 'depth_limit': 42 | return $this->renderLockedHeader($v, 'DEPTH LIMIT'); 43 | case 'array_limit': 44 | return $this->renderLockedHeader($v, 'ARRAY LIMIT'); 45 | } 46 | 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Renderer/Text/PluginInterface.php: -------------------------------------------------------------------------------- 1 | getRepresentation('splfileinfo'); 38 | 39 | if (!$r instanceof SplFileInfoRepresentation) { 40 | return null; 41 | } 42 | 43 | $out = ''; 44 | 45 | $c = $v->getContext(); 46 | 47 | if (0 === $c->getDepth()) { 48 | $out .= $this->renderer->colorTitle($this->renderer->renderTitle($v)).PHP_EOL; 49 | } 50 | 51 | $out .= $this->renderer->renderHeader($v); 52 | if (null !== $v->getDisplayValue()) { 53 | $out .= ' =>'; 54 | } 55 | $out .= ' '.$this->renderer->colorValue($this->renderer->escape($r->getValue())).PHP_EOL; 56 | 57 | return $out; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Value/ArrayValue.php: -------------------------------------------------------------------------------- 1 | size = $size; 48 | $this->contents = $contents; 49 | } 50 | 51 | public function getSize(): int 52 | { 53 | return $this->size; 54 | } 55 | 56 | /** @psalm-return AbstractValue[] */ 57 | public function getContents() 58 | { 59 | return $this->contents; 60 | } 61 | 62 | public function getDisplaySize(): string 63 | { 64 | return (string) $this->size; 65 | } 66 | 67 | public function getDisplayChildren(): array 68 | { 69 | return $this->contents; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Value/ClosedResourceValue.php: -------------------------------------------------------------------------------- 1 | '; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Value/Context/BaseContext.php: -------------------------------------------------------------------------------- 1 | name = $name; 51 | } 52 | 53 | public function getName() 54 | { 55 | return $this->name; 56 | } 57 | 58 | public function getDepth(): int 59 | { 60 | return $this->depth; 61 | } 62 | 63 | public function getOperator(): ?string 64 | { 65 | return null; 66 | } 67 | 68 | public function isRef(): bool 69 | { 70 | return $this->reference; 71 | } 72 | 73 | /** @psalm-param ?class-string $scope */ 74 | public function isAccessible(?string $scope): bool 75 | { 76 | return true; 77 | } 78 | 79 | public function getAccessPath(): ?string 80 | { 81 | return $this->access_path; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Value/Context/ClassConstContext.php: -------------------------------------------------------------------------------- 1 | owner_class.'::'.$this->name; 37 | } 38 | 39 | public function getOperator(): string 40 | { 41 | return '::'; 42 | } 43 | 44 | public function getModifiers(): string 45 | { 46 | $final = $this->final ? 'final ' : ''; 47 | 48 | return $final.$this->getAccess().' const'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Value/Context/ClassDeclaredContext.php: -------------------------------------------------------------------------------- 1 | access = $access; 49 | } 50 | 51 | abstract public function getModifiers(): string; 52 | 53 | /** @psalm-param ?class-string $scope */ 54 | public function isAccessible(?string $scope): bool 55 | { 56 | if (__PHP_Incomplete_Class::class === $this->owner_class) { 57 | return false; 58 | } 59 | 60 | if (self::ACCESS_PUBLIC === $this->access) { 61 | return true; 62 | } 63 | 64 | if (null === $scope) { 65 | return false; 66 | } 67 | 68 | if (self::ACCESS_PRIVATE === $this->access) { 69 | return $scope === $this->owner_class; 70 | } 71 | 72 | if (\is_a($scope, $this->owner_class, true)) { 73 | return true; 74 | } 75 | 76 | if (\is_a($this->owner_class, $scope, true)) { 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | protected function getAccess(): string 84 | { 85 | switch ($this->access) { 86 | case self::ACCESS_PUBLIC: 87 | return 'public'; 88 | case self::ACCESS_PROTECTED: 89 | return 'protected'; 90 | case self::ACCESS_PRIVATE: 91 | return 'private'; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Value/Context/ClassOwnedContext.php: -------------------------------------------------------------------------------- 1 | owner_class = $owner_class; 42 | } 43 | 44 | public function getName(): string 45 | { 46 | return (string) $this->name; 47 | } 48 | 49 | public function getOperator(): string 50 | { 51 | return '->'; 52 | } 53 | 54 | /** @psalm-param ?class-string $scope */ 55 | public function isAccessible(?string $scope): bool 56 | { 57 | return __PHP_Incomplete_Class::class !== $this->owner_class; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Value/Context/ContextInterface.php: -------------------------------------------------------------------------------- 1 | access) { 38 | case self::ACCESS_PUBLIC: 39 | if (self::ACCESS_PRIVATE === $this->access_set) { 40 | return 'private(set)'; 41 | } 42 | if (self::ACCESS_PROTECTED === $this->access_set) { 43 | return 'protected(set)'; 44 | } 45 | 46 | return 'public'; 47 | 48 | case self::ACCESS_PROTECTED: 49 | if (self::ACCESS_PRIVATE === $this->access_set) { 50 | return 'protected private(set)'; 51 | } 52 | 53 | return 'protected'; 54 | 55 | case self::ACCESS_PRIVATE: 56 | return 'private'; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Value/Context/PropertyContext.php: -------------------------------------------------------------------------------- 1 | */ 40 | public int $hooks = self::HOOK_NONE; 41 | public ?string $hook_set_type = null; 42 | 43 | public function getModifiers(): string 44 | { 45 | $out = $this->getAccess(); 46 | 47 | if ($this->readonly) { 48 | $out .= ' readonly'; 49 | } 50 | 51 | return $out; 52 | } 53 | 54 | public function getHooks(): ?string 55 | { 56 | if (self::HOOK_NONE === $this->hooks) { 57 | return null; 58 | } 59 | 60 | $out = '{ '; 61 | if ($this->hooks & self::HOOK_GET) { 62 | if ($this->hooks & self::HOOK_GET_REF) { 63 | $out .= '&'; 64 | } 65 | $out .= 'get; '; 66 | } 67 | if ($this->hooks & self::HOOK_SET) { 68 | if ($this->hooks & self::HOOK_SET_TYPE && '' !== ($this->hook_set_type ?? '')) { 69 | $out .= 'set('.$this->hook_set_type.'); '; 70 | } else { 71 | $out .= 'set; '; 72 | } 73 | } 74 | $out .= '}'; 75 | 76 | return $out; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Value/Context/StaticPropertyContext.php: -------------------------------------------------------------------------------- 1 | owner_class.'::$'.$this->name; 37 | } 38 | 39 | public function getOperator(): string 40 | { 41 | return '::'; 42 | } 43 | 44 | public function getModifiers(): string 45 | { 46 | $final = $this->final ? 'final ' : ''; 47 | 48 | return $final.$this->getAccess().' static'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Value/DateTimeValue.php: -------------------------------------------------------------------------------- 1 | dt = clone $dt; 43 | } 44 | 45 | public function getHint(): string 46 | { 47 | return parent::getHint() ?? 'datetime'; 48 | } 49 | 50 | public function getDisplayValue(): string 51 | { 52 | $stamp = $this->dt->format('Y-m-d H:i:s'); 53 | if ((int) ($micro = $this->dt->format('u'))) { 54 | $stamp .= '.'.$micro; 55 | } 56 | $stamp .= $this->dt->format(' P'); 57 | 58 | $tzn = $this->dt->getTimezone()->getName(); 59 | if ('+' !== $tzn[0] && '-' !== $tzn[0]) { 60 | $stamp .= $this->dt->format(' T'); 61 | } 62 | 63 | return $stamp; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Value/DeclaredCallableBag.php: -------------------------------------------------------------------------------- 1 | internal = $callable->isInternal(); 60 | $t = $callable->getFileName(); 61 | $this->filename = false === $t ? null : $t; 62 | $t = $callable->getStartLine(); 63 | $this->startline = false === $t ? null : $t; 64 | $t = $callable->getEndLine(); 65 | $this->endline = false === $t ? null : $t; 66 | $t = $callable->getDocComment(); 67 | $this->docstring = false === $t ? null : $t; 68 | $this->return_reference = $callable->returnsReference(); 69 | 70 | $rt = $callable->getReturnType(); 71 | if ($rt) { 72 | $this->returntype = Utils::getTypeString($rt); 73 | } 74 | 75 | $parameters = []; 76 | foreach ($callable->getParameters() as $param) { 77 | $parameters[] = new ParameterBag($param); 78 | } 79 | $this->parameters = $parameters; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Value/DomNodeListValue.php: -------------------------------------------------------------------------------- 1 | length = $node->length; 46 | } 47 | 48 | public function getLength(): int 49 | { 50 | return $this->length; 51 | } 52 | 53 | public function getDisplaySize(): string 54 | { 55 | return (string) $this->length; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Value/DomNodeValue.php: -------------------------------------------------------------------------------- 1 | enumval = $enumval; 44 | } 45 | 46 | public function getHint(): string 47 | { 48 | return parent::getHint() ?? 'enum'; 49 | } 50 | 51 | public function getDisplayType(): string 52 | { 53 | return $this->classname.'::'.$this->enumval->name; 54 | } 55 | 56 | public function getDisplayValue(): ?string 57 | { 58 | if ($this->enumval instanceof BackedEnum) { 59 | if (\is_string($this->enumval->value)) { 60 | return '"'.$this->enumval->value.'"'; 61 | } 62 | 63 | return (string) $this->enumval->value; 64 | } 65 | 66 | return null; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Value/FixedWidthValue.php: -------------------------------------------------------------------------------- 1 | value = $value; 53 | } else { 54 | throw new InvalidArgumentException('FixedWidthValue can only contain fixed width types, got '.$type); 55 | } 56 | } 57 | 58 | /** 59 | * @psalm-api 60 | * 61 | * @psalm-return FixedWidthType 62 | */ 63 | public function getValue() 64 | { 65 | return $this->value; 66 | } 67 | 68 | public function getDisplaySize(): ?string 69 | { 70 | return null; 71 | } 72 | 73 | public function getDisplayValue(): ?string 74 | { 75 | if ('boolean' === $this->type) { 76 | return ((bool) $this->value) ? 'true' : 'false'; 77 | } 78 | 79 | if ('integer' === $this->type || 'double' === $this->type) { 80 | return (string) $this->value; 81 | } 82 | 83 | return null; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Value/FunctionValue.php: -------------------------------------------------------------------------------- 1 | callable_bag = $bag; 45 | 46 | if ($this->callable_bag->internal) { 47 | $this->definition_rep = null; 48 | 49 | return; 50 | } 51 | 52 | /** 53 | * @psalm-var string $this->callable_bag->filename 54 | * @psalm-var int $this->callable_bag->startline 55 | * Psalm issue #11121 56 | */ 57 | $this->definition_rep = new CallableDefinitionRepresentation( 58 | $this->callable_bag->filename, 59 | $this->callable_bag->startline, 60 | $this->callable_bag->docstring 61 | ); 62 | $this->addRepresentation($this->definition_rep); 63 | } 64 | 65 | public function getCallableBag(): DeclaredCallableBag 66 | { 67 | return $this->callable_bag; 68 | } 69 | 70 | /** @psalm-api */ 71 | public function getDefinitionRepresentation(): ?CallableDefinitionRepresentation 72 | { 73 | return $this->definition_rep; 74 | } 75 | 76 | public function getDisplayName(): string 77 | { 78 | return $this->context->getName().'('.$this->callable_bag->getParams().')'; 79 | } 80 | 81 | public function getDisplayValue(): ?string 82 | { 83 | if ($this->definition_rep instanceof CallableDefinitionRepresentation) { 84 | return $this->definition_rep->getDocstringFirstLine(); 85 | } 86 | 87 | return parent::getDisplayValue(); 88 | } 89 | 90 | public function getPhpDocUrl(): ?string 91 | { 92 | if (!$this->callable_bag->internal) { 93 | return null; 94 | } 95 | 96 | return 'https://www.php.net/function.'.\str_replace('_', '-', \strtolower((string) $this->context->getName())); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Value/InstanceValue.php: -------------------------------------------------------------------------------- 1 | 49 | */ 50 | protected ?array $children = null; 51 | 52 | /** @psalm-param class-string $classname */ 53 | public function __construct( 54 | ContextInterface $context, 55 | string $classname, 56 | string $spl_object_hash, 57 | int $spl_object_id 58 | ) { 59 | parent::__construct($context, 'object'); 60 | $this->classname = $classname; 61 | $this->spl_object_hash = $spl_object_hash; 62 | $this->spl_object_id = $spl_object_id; 63 | } 64 | 65 | /** @psalm-return class-string */ 66 | public function getClassName(): string 67 | { 68 | return $this->classname; 69 | } 70 | 71 | public function getSplObjectHash(): string 72 | { 73 | return $this->spl_object_hash; 74 | } 75 | 76 | public function getSplObjectId(): int 77 | { 78 | return $this->spl_object_id; 79 | } 80 | 81 | /** @psalm-param null|list $children */ 82 | public function setChildren(?array $children): void 83 | { 84 | $this->children = $children; 85 | } 86 | 87 | /** @psalm-return null|list */ 88 | public function getChildren(): ?array 89 | { 90 | return $this->children; 91 | } 92 | 93 | public function getDisplayType(): string 94 | { 95 | return $this->classname; 96 | } 97 | 98 | public function getDisplaySize(): ?string 99 | { 100 | if (null === $this->children) { 101 | return null; 102 | } 103 | 104 | return (string) \count($this->children); 105 | } 106 | 107 | public function getDisplayChildren(): array 108 | { 109 | return $this->children ?? []; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Value/MicrotimeValue.php: -------------------------------------------------------------------------------- 1 | context = $old->context; 38 | $this->type = $old->type; 39 | $this->flags = $old->flags; 40 | $this->representations = $old->representations; 41 | $this->wrapped = $old; 42 | } 43 | 44 | public function getHint(): string 45 | { 46 | return parent::getHint() ?? 'microtime'; 47 | } 48 | 49 | public function getDisplaySize(): ?string 50 | { 51 | return $this->wrapped->getDisplaySize(); 52 | } 53 | 54 | public function getDisplayValue(): ?string 55 | { 56 | return $this->wrapped->getDisplayValue(); 57 | } 58 | 59 | public function getDisplayType(): string 60 | { 61 | return $this->wrapped->getDisplayType(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Value/ParameterBag.php: -------------------------------------------------------------------------------- 1 | name = $param->getName(); 49 | $this->position = $param->getPosition(); 50 | $this->ref = $param->isPassedByReference(); 51 | 52 | $this->type_hint = ($type = $param->getType()) ? Utils::getTypeString($type) : null; 53 | 54 | if ($param->isDefaultValueAvailable()) { 55 | $default = $param->getDefaultValue(); 56 | switch (\gettype($default)) { 57 | case 'NULL': 58 | $this->default = 'null'; 59 | break; 60 | case 'boolean': 61 | $this->default = $default ? 'true' : 'false'; 62 | break; 63 | case 'array': 64 | $this->default = \count($default) ? 'array(...)' : 'array()'; 65 | break; 66 | case 'double': 67 | case 'integer': 68 | case 'string': 69 | $this->default = \var_export($default, true); 70 | break; 71 | case 'object': 72 | $this->default = 'object('.\get_class($default).')'; 73 | break; 74 | default: 75 | $this->default = \gettype($default); 76 | break; 77 | } 78 | } else { 79 | $this->default = null; 80 | } 81 | } 82 | 83 | public function __toString() 84 | { 85 | $type = $this->type_hint; 86 | if (null !== $type) { 87 | $type .= ' '; 88 | } 89 | 90 | $default = $this->default; 91 | if (null !== $default) { 92 | $default = ' = '.$default; 93 | } 94 | 95 | $ref = $this->ref ? '&' : ''; 96 | 97 | return $type.$ref.'$'.$this->name.$default; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Value/ParameterHoldingTrait.php: -------------------------------------------------------------------------------- 1 | parameters as $p) { 44 | $out[] = (string) $p; 45 | } 46 | 47 | return \implode(', ', $out); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Value/Representation/AbstractRepresentation.php: -------------------------------------------------------------------------------- 1 | label = $label; 42 | /** @psalm-var string $name */ 43 | $name = \preg_replace('/[^a-z0-9]+/', '_', \strtolower($name ?? $label)); 44 | $this->name = $name; 45 | $this->implicit_label = $implicit_label; 46 | } 47 | 48 | public function getLabel(): string 49 | { 50 | return $this->label; 51 | } 52 | 53 | public function getName(): string 54 | { 55 | return $this->name; 56 | } 57 | 58 | public function labelIsImplicit(): bool 59 | { 60 | return $this->implicit_label; 61 | } 62 | 63 | public function getHint(): ?string 64 | { 65 | return null; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Value/Representation/BinaryRepresentation.php: -------------------------------------------------------------------------------- 1 | value = $value; 39 | } 40 | 41 | public function getHint(): string 42 | { 43 | return 'binary'; 44 | } 45 | 46 | public function getValue(): string 47 | { 48 | return $this->value; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Value/Representation/ContainerRepresentation.php: -------------------------------------------------------------------------------- 1 | 39 | */ 40 | protected array $contents; 41 | 42 | /** @psalm-param non-empty-array $contents */ 43 | public function __construct(string $label, array $contents, ?string $name = null, bool $implicit_label = false) 44 | { 45 | if ([] === $contents) { 46 | throw new InvalidArgumentException("ContainerRepresentation can't take empty list"); 47 | } 48 | 49 | parent::__construct($label, $name, $implicit_label); 50 | $this->contents = $contents; 51 | } 52 | 53 | /** @psalm-return non-empty-array */ 54 | public function getContents(): array 55 | { 56 | return $this->contents; 57 | } 58 | 59 | public function getLabel(): string 60 | { 61 | return parent::getLabel().' ('.\count($this->contents).')'; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Value/Representation/ProfileRepresentation.php: -------------------------------------------------------------------------------- 1 | complexity = $complexity; 41 | } 42 | 43 | public function getHint(): string 44 | { 45 | return 'profiling'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Value/Representation/RepresentationInterface.php: -------------------------------------------------------------------------------- 1 | value = $value; 50 | } 51 | 52 | /** @psalm-return non-empty-string */ 53 | public function getValue(): string 54 | { 55 | return $this->value; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Value/Representation/TableRepresentation.php: -------------------------------------------------------------------------------- 1 | $contents */ 35 | public function __construct(array $contents, ?string $name = null) 36 | { 37 | parent::__construct('Table', $contents, $name, false); 38 | } 39 | 40 | public function getHint(): string 41 | { 42 | return 'table'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Value/Representation/ValueRepresentation.php: -------------------------------------------------------------------------------- 1 | value = $value; 41 | } 42 | 43 | public function getValue(): AbstractValue 44 | { 45 | return $this->value; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Value/ResourceValue.php: -------------------------------------------------------------------------------- 1 | resource_type = $resource_type; 41 | } 42 | 43 | public function getDisplayType(): string 44 | { 45 | return $this->resource_type.' resource'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Value/SimpleXMLElementValue.php: -------------------------------------------------------------------------------- 1 | $children */ 39 | public function __construct( 40 | ContextInterface $context, 41 | SimpleXMLElement $element, 42 | array $children, 43 | ?string $text_content 44 | ) { 45 | parent::__construct($context, \get_class($element), \spl_object_hash($element), \spl_object_id($element)); 46 | 47 | $this->children = $children; 48 | $this->text_content = $text_content; 49 | } 50 | 51 | public function getHint(): string 52 | { 53 | return parent::getHint() ?? 'simplexml_element'; 54 | } 55 | 56 | public function getDisplaySize(): ?string 57 | { 58 | if ((bool) $this->children) { 59 | return (string) \count($this->children); 60 | } 61 | 62 | if (null !== $this->text_content) { 63 | return (string) \strlen($this->text_content); 64 | } 65 | 66 | return null; 67 | } 68 | 69 | public function getDisplayValue(): ?string 70 | { 71 | if ((bool) $this->children) { 72 | return parent::getDisplayValue(); 73 | } 74 | 75 | if (null !== $this->text_content) { 76 | return '"'.$this->text_content.'"'; 77 | } 78 | 79 | return null; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Value/SplFileInfoValue.php: -------------------------------------------------------------------------------- 1 | path = $info->getPathname(); 47 | 48 | try { 49 | // SplFileInfo::getRealPath will return cwd when path is '' 50 | if ('' !== $this->path && $info->getRealPath()) { 51 | $this->filesize = $info->getSize(); 52 | } 53 | } catch (RuntimeException $e) { 54 | if (false === \strpos($e->getMessage(), ' open_basedir ')) { 55 | throw $e; // @codeCoverageIgnore 56 | } 57 | } 58 | } 59 | 60 | public function getHint(): string 61 | { 62 | return parent::getHint() ?? 'splfileinfo'; 63 | } 64 | 65 | /** @psalm-api */ 66 | public function getFileSize(): ?int 67 | { 68 | return $this->filesize; 69 | } 70 | 71 | public function getDisplaySize(): ?string 72 | { 73 | if (null === $this->filesize) { 74 | return null; 75 | } 76 | 77 | $size = Utils::getHumanReadableBytes($this->filesize); 78 | 79 | return $size['value'].$size['unit']; 80 | } 81 | 82 | public function getDisplayValue(): ?string 83 | { 84 | $shortpath = Utils::shortenPath($this->path); 85 | 86 | if ($shortpath !== $this->path) { 87 | return $shortpath; 88 | } 89 | 90 | return parent::getDisplayValue(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Value/StreamValue.php: -------------------------------------------------------------------------------- 1 | stream_meta = $stream_meta; 50 | $this->uri = $uri; 51 | 52 | if ($stream_meta) { 53 | $this->addRepresentation(new ContainerRepresentation('Stream', $stream_meta, null, true)); 54 | } 55 | } 56 | 57 | public function getHint(): string 58 | { 59 | return parent::getHint() ?? 'stream'; 60 | } 61 | 62 | public function getDisplayValue(): ?string 63 | { 64 | if (null === $this->uri) { 65 | return null; 66 | } 67 | 68 | if ('/' === $this->uri[0] && \stream_is_local($this->uri)) { 69 | return Utils::shortenPath($this->uri); 70 | } 71 | 72 | return $this->uri; 73 | } 74 | 75 | public function getDisplayChildren(): array 76 | { 77 | return $this->stream_meta; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Value/StringValue.php: -------------------------------------------------------------------------------- 1 | value = $value; 56 | $this->encoding = $encoding; 57 | $this->length = \strlen($value); 58 | } 59 | 60 | public function getValue(): string 61 | { 62 | return $this->value; 63 | } 64 | 65 | public function getValueUtf8(): string 66 | { 67 | if (false === $this->encoding) { 68 | throw new DomainException('StringValue with no encoding can\'t be converted to UTF-8'); 69 | } 70 | 71 | if ('ASCII' === $this->encoding || 'UTF-8' === $this->encoding) { 72 | return $this->value; 73 | } 74 | 75 | /** @psalm-var string $encoded */ 76 | $encoded = \mb_convert_encoding($this->value, 'UTF-8', $this->encoding); 77 | 78 | return $encoded; 79 | } 80 | 81 | /** @psalm-api */ 82 | public function getLength(): int 83 | { 84 | return $this->length; 85 | } 86 | 87 | /** @psalm-return Encoding */ 88 | public function getEncoding() 89 | { 90 | return $this->encoding; 91 | } 92 | 93 | public function getDisplayType(): string 94 | { 95 | if (false === $this->encoding) { 96 | return 'binary '.$this->type; 97 | } 98 | 99 | if ('ASCII' === $this->encoding) { 100 | return $this->type; 101 | } 102 | 103 | return $this->encoding.' '.$this->type; 104 | } 105 | 106 | public function getDisplaySize(): string 107 | { 108 | return (string) $this->length; 109 | } 110 | 111 | public function getDisplayValue(): string 112 | { 113 | return '"'.$this->value.'"'; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Value/ThrowableValue.php: -------------------------------------------------------------------------------- 1 | message = $throw->getMessage(); 43 | } 44 | 45 | public function getDisplayValue(): string 46 | { 47 | return '"'.$this->message.'"'; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Value/TraceValue.php: -------------------------------------------------------------------------------- 1 | size > 0) { 45 | return parent::getDisplaySize(); 46 | } 47 | 48 | return 'empty'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Value/UninitializedValue.php: -------------------------------------------------------------------------------- 1 |