Skip to content

Commit

Permalink
Merge 66db455 into 19fdd9b
Browse files Browse the repository at this point in the history
  • Loading branch information
markstory committed Jan 6, 2020
2 parents 19fdd9b + 66db455 commit 079c422
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 43 deletions.
70 changes: 39 additions & 31 deletions src/Error/Debugger.php
Original file line number Diff line number Diff line change
Expand Up @@ -495,18 +495,19 @@ protected static function _highlight(string $str): string
*/
public static function exportVar($var, int $depth = 3): string
{
return static::_export($var, $depth, 0);
$context = new DumpContext($depth);

return static::_export($var, $context);
}

/**
* Protected export function used to keep track of indentation and recursion.
*
* @param mixed $var The variable to dump.
* @param int $depth The remaining depth.
* @param int $indent The current indentation level.
* @param \Cake\Error\DumpContext $context Dump context
* @return string The dumped variable.
*/
protected static function _export($var, int $depth, int $indent): string
protected static function _export($var, DumpContext $context): string
{
switch (static::getType($var)) {
case 'boolean':
Expand All @@ -522,15 +523,15 @@ protected static function _export($var, int $depth, int $indent): string

return "'" . $var . "'";
case 'array':
return static::_array($var, $depth - 1, $indent + 1);
return static::_array($var, $context->withAddedDepthAndIndent());
case 'resource':
return strtolower(gettype($var));
case 'null':
return 'null';
case 'unknown':
return 'unknown';
default:
return static::_object($var, $depth - 1, $indent + 1);
return static::_object($var, $context->withAddedDepthAndIndent());
}
}

Expand All @@ -548,21 +549,22 @@ protected static function _export($var, int $depth, int $indent): string
* - schema
*
* @param array $var The array to export.
* @param int $depth The current depth, used for recursion tracking.
* @param int $indent The current indentation level.
* @param \Cake\Error\DumpContext $context The current dump context.
* @return string Exported array.
*/
protected static function _array(array $var, int $depth, int $indent): string
protected static function _array(array $var, DumpContext $context): string
{
$out = '[';
$break = $end = '';
if (!empty($var)) {
$indent = $context->getIndent();
$break = "\n" . str_repeat("\t", $indent);
$end = "\n" . str_repeat("\t", $indent - 1);
}
$vars = [];

if ($depth >= 0) {
$remaining = $context->remainingDepth();
if ($remaining >= 0) {
$outputMask = (array)static::outputMask();
foreach ($var as $key => $val) {
// Sniff for globals as !== explodes in < 5.4
Expand All @@ -571,9 +573,9 @@ protected static function _array(array $var, int $depth, int $indent): string
} elseif (array_key_exists($key, $outputMask)) {
$val = (string)$outputMask[$key];
} elseif ($val !== $var) {
$val = static::_export($val, $depth, $indent);
$val = static::_export($val, $context);
}
$vars[] = $break . static::exportVar($key) .
$vars[] = $break . static::_export($key, $context) .
' => ' .
$val;
}
Expand All @@ -588,40 +590,46 @@ protected static function _array(array $var, int $depth, int $indent): string
* Handles object to string conversion.
*
* @param object $var Object to convert.
* @param int $depth The current depth, used for tracking recursion.
* @param int $indent The current indentation level.
* @param \Cake\Error\DumpContext $context The dump context.
* @return string
* @see \Cake\Error\Debugger::exportVar()
*/
protected static function _object(object $var, int $depth, int $indent): string
protected static function _object(object $var, DumpContext $context): string
{
$out = '';
$props = [];

$isRef = $context->hasReference($var);
$refNum = $context->getReferenceId($var);

$className = get_class($var);
$out .= 'object(' . $className . ') {';
$out .= "object({$className}) #{$refNum} {";
$indent = $context->getIndent();
$break = "\n" . str_repeat("\t", $indent);
$end = "\n" . str_repeat("\t", $indent - 1);

if ($depth > 0 && method_exists($var, '__debugInfo')) {
try {
return $out . "\n" .
substr(static::_array($var->__debugInfo(), $depth - 1, $indent), 1, -1) .
$end . '}';
} catch (Exception $e) {
$message = $e->getMessage();

return $out . "\n(unable to export object: $message)\n }";
$remaining = $context->remainingDepth();
if ($remaining > 0 && $isRef === false) {
if (method_exists($var, '__debugInfo')) {
try {
return $out . "\n" .
substr(static::_array($var->__debugInfo(), $context->withAddedDepth()), 1, -1) .
$end . '}';
} catch (Exception $e) {
$message = $e->getMessage();

return $out . "\n(unable to export object: $message)\n }";
}
}
}

if ($depth > 0) {
$outputMask = (array)static::outputMask();
$objectVars = get_object_vars($var);
foreach ($objectVars as $key => $value) {
$value = array_key_exists($key, $outputMask)
? $outputMask[$key]
: static::_export($value, $depth - 1, $indent);
if (array_key_exists($key, $outputMask)) {
$value = $outputMask[$key];
} else {
$value = static::_export($value, $context->withAddedDepth());
}
$props[] = "$key => " . $value;
}

Expand All @@ -637,7 +645,7 @@ protected static function _object(object $var, int $depth, int $indent): string
$reflectionProperty->setAccessible(true);
$property = $reflectionProperty->getValue($var);

$value = static::_export($property, $depth - 1, $indent);
$value = static::_export($property, $context->withAddedDepth());
$key = $reflectionProperty->name;
$props[] = sprintf(
'[%s] %s => %s',
Expand Down
140 changes: 140 additions & 0 deletions src/Error/DumpContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php
declare(strict_types=1);

/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 4.1.0
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Error;

use SplObjectStorage;

/**
* Context tracking for Debugger::exportVar()
*
* This class is used by Debugger to track element depth,
* and indentation. In the longer term indentation should be extracted
* into a formatter (cli/html).
*
* @internal
*/
class DumpContext
{
/**
* @var int
*/
private $maxDepth = 0;

/**
* @var int
*/
private $depth = 0;

/**
* @var int
*/
private $indent = 0;

/**
* @var \SplObjectStorage
*/
private $refs;

/**
* Constructor
*
* @param int $maxDepth The desired depth of dump output.
*/
public function __construct(int $maxDepth)
{
$this->maxDepth = $maxDepth;
$this->refs = new SplObjectStorage();
}

/**
* Return a clone with increased depth.
*
* @return static
*/
public function withAddedDepth()
{
$new = clone $this;
$new->depth += 1;

return $new;
}

/**
* Return a clone with increased depth and indent
*
* @return static
*/
public function withAddedDepthAndIndent()
{
$new = clone $this;
$new->depth += 1;
$new->indent += 1;

return $new;
}

/**
* Get the current indent level.
*
* @return int
*/
public function getIndent(): int
{
return $this->indent;
}

/**
* Get the remaining depth levels
*
* @return int
*/
public function remainingDepth(): int
{
return $this->maxDepth - $this->depth;
}

/**
* Get the reference ID for an object.
*
* If this object does not exist in the reference storage,
* it will be added and the id will be returned.
*
* @param object $object The object to get a reference for.
* @return int
*/
public function getReferenceId(object $object): int
{
if ($this->refs->contains($object)) {
return $this->refs[$object];
}
$refId = $this->refs->count();
$this->refs->attach($object, $refId);

return $refId;
}

/**
* Check whether an object has been seen before.
*
* @param object $object The object to get a reference for.
* @return bool
*/
public function hasReference(object $object): bool
{
return $this->refs->contains($object);
}
}

0 comments on commit 079c422

Please sign in to comment.