-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
VarDumper and DebugBundle #10640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
VarDumper and DebugBundle #10640
Changes from 1 commit
eec5c92
4bf9300
07135a0
5b7ae28
3ddbf4b
c91bc83
da3e50a
0a92c08
c426d8b
0266072
1d5e3f4
fa81544
e6dde33
5eaa187
a69e962
297d373
9dea601
eb98c81
8d5d970
c8746a4
0d8a942
081363c
49f13c6
de05cd9
e4e00ef
5f59811
a8d81e4
d43ae82
0f8d30f
2e167ba
80fd736
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,9 @@ | |
|
||
namespace Symfony\Component\VarDumper\Cloner; | ||
|
||
use Symfony\Component\VarDumper\Dumper\DumperInternalsInterface; | ||
use Symfony\Component\VarDumper\Dumper\Cursor; | ||
|
||
/** | ||
* @author Nicolas Grekas <p@tchwork.com> | ||
*/ | ||
|
@@ -30,4 +33,169 @@ public function getRawData() | |
{ | ||
return $this->data; | ||
} | ||
|
||
/** | ||
* Dumps data with a DumperInternalsInterface dumper. | ||
*/ | ||
public function dump(DumperInternalsInterface $dumper) | ||
{ | ||
$refs = array(0); | ||
$this->dumpItem($dumper, new Cursor, $refs, $this->data[0][0]); | ||
} | ||
|
||
/** | ||
* Breadth-first dumping of items. | ||
* | ||
* @param DumperInternalsInterface $dumper The dumper being used for dumping. | ||
* @param Cursor $cursor A cursor used for tracking dumper state position. | ||
* @param array &$refs A map of all references discovered while dumping. | ||
* @param mixed $item A stub stdClass or the original value being dumped. | ||
*/ | ||
private function dumpItem($dumper, $cursor, &$refs, $item) | ||
{ | ||
$cursor->refIndex = $cursor->refTo = $cursor->refIsHard = false; | ||
|
||
if ($item instanceof \stdClass) { | ||
if (property_exists($item, 'val')) { | ||
if (isset($item->ref)) { | ||
if (isset($refs[$r = $item->ref])) { | ||
$cursor->refTo = $refs[$r]; | ||
$cursor->refIsHard = true; | ||
} else { | ||
$cursor->refIndex = $refs[$r] = ++$refs[0]; | ||
} | ||
} | ||
$item = $item->val; | ||
} | ||
if (isset($item->ref)) { | ||
if (isset($refs[$r = $item->ref])) { | ||
if (false === $cursor->refTo) { | ||
$cursor->refTo = $refs[$r]; | ||
$cursor->refIsHard = isset($item->count); | ||
} | ||
} elseif (false !== $cursor->refIndex) { | ||
$refs[$r] = $cursor->refIndex; | ||
} else { | ||
$cursor->refIndex = $refs[$r] = ++$refs[0]; | ||
} | ||
} | ||
$cut = isset($item->cut) ? $item->cut : 0; | ||
|
||
if (isset($item->pos) && false === $cursor->refTo) { | ||
$children = $this->data[$item->pos]; | ||
|
||
if ($cursor->stop) { | ||
if ($cut >= 0) { | ||
$cut += count($children); | ||
} | ||
$children = array(); | ||
} | ||
} else { | ||
$children = array(); | ||
} | ||
switch (true) { | ||
case isset($item->bin): | ||
$dumper->dumpString($cursor, $item->bin, true, $cut); | ||
|
||
return; | ||
|
||
case isset($item->str): | ||
$dumper->dumpString($cursor, $item->str, false, $cut); | ||
|
||
return; | ||
|
||
case isset($item->count): | ||
$dumper->enterArray($cursor, $item->count, !empty($item->indexed), (bool) $children); | ||
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, empty($item->indexed) ? $cursor::HASH_ASSOC : $cursor::HASH_INDEXED); | ||
$dumper->leaveArray($cursor, $item->count, !empty($item->indexed), (bool) $children, $cut); | ||
|
||
return; | ||
|
||
case isset($item->class): | ||
$dumper->enterObject($cursor, $item->class, (bool) $children); | ||
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $cursor::HASH_OBJECT); | ||
$dumper->leaveObject($cursor, $item->class, (bool) $children, $cut); | ||
|
||
return; | ||
|
||
case isset($item->res): | ||
$dumper->enterResource($cursor, $item->res, (bool) $children); | ||
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $cursor::HASH_RESOURCE); | ||
$dumper->leaveResource($cursor, $item->res, (bool) $children, $cut); | ||
|
||
return; | ||
} | ||
} | ||
|
||
if ('array' === $type = gettype($item)) { | ||
$dumper->enterArray($cursor, 0, true, 0, 0); | ||
$dumper->leaveArray($cursor, 0, true, 0, 0); | ||
} else { | ||
$dumper->dumpScalar($cursor, $type, $item); | ||
} | ||
} | ||
|
||
/** | ||
* Dumps children of hash structures. | ||
* | ||
* @param DumperInternalsInterface $dumper | ||
* @param Cursor $parentCursor The cursor of the parent hash. | ||
* @param array &$refs A map of all references discovered while dumping. | ||
* @param array $children The children to dump. | ||
* @param int $hashCut The number of items removed from the original hash. | ||
* @param int $hashType A Cursor::HASH_* const. | ||
* | ||
* @return int The final number of removed items. | ||
*/ | ||
private function dumpChildren($dumper, $parentCursor, &$refs, $children, $hashCut, $hashType) | ||
{ | ||
if ($children) { | ||
$cursor = clone $parentCursor; | ||
++$cursor->depth; | ||
$cursor->hashType = $hashType; | ||
$cursor->hashIndex = 0; | ||
$cursor->hashLength = count($children); | ||
$cursor->hashCut = $hashCut; | ||
foreach ($children as $cursor->hashKey => $child) { | ||
$this->dumpItem($dumper, $cursor, $refs, $child); | ||
++$cursor->hashIndex; | ||
if ($cursor->stop) { | ||
$parentCursor->stop = true; | ||
|
||
return $hashCut >= 0 ? $hashCut + $children - $cursor->hashIndex : $hashCut; | ||
} | ||
} | ||
} | ||
|
||
return $hashCut; | ||
} | ||
|
||
/** | ||
* Portable variant of utf8_encode() | ||
* | ||
* @param string $s | ||
* | ||
* @return string | ||
* | ||
* @internal | ||
*/ | ||
public static function utf8Encode($s) | ||
{ | ||
if (function_exists('iconv')) { | ||
return iconv('CP1252', 'UTF-8', $s); | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no And what about using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. iconv is bundled into PHP as a default extension, whereas mbstring is an optional extension. |
||
$s .= $s; | ||
$len = strlen($s); | ||
|
||
for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) { | ||
switch (true) { | ||
case $s[$i] < "\x80": $s[$j] = $s[$i]; break; | ||
case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break; | ||
default: $s[$j] = "\xC3"; $s[++$j] = chr(ord($s[$i]) - 64); break; | ||
} | ||
} | ||
|
||
return substr($s, 0, $j); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\VarDumper\Dumper; | ||
|
||
/** | ||
* Represents the current state of a dumper while dumping. | ||
* | ||
* @author Nicolas Grekas <p@tchwork.com> | ||
*/ | ||
class Cursor | ||
{ | ||
const HASH_INDEXED = 'indexed-array'; | ||
const HASH_ASSOC = 'associative-array'; | ||
const HASH_OBJECT = 'object'; | ||
const HASH_RESOURCE = 'resource'; | ||
|
||
public $depth = 0; | ||
public $refIndex = false; | ||
public $refTo = false; | ||
public $refIsHard = false; | ||
public $hashType; | ||
public $hashKey; | ||
public $hashIndex = 0; | ||
public $hashLength = 0; | ||
public $hashCut = 0; | ||
public $stop = false; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\VarDumper\Dumper; | ||
|
||
use Symfony\Component\VarDumper\Cloner\Data; | ||
|
||
/** | ||
* DataDumperInterface for dumping Data objects. | ||
* | ||
* @author Nicolas Grekas <p@tchwork.com> | ||
*/ | ||
interface DataDumperInterface | ||
{ | ||
/** | ||
* Dumps a Data object. | ||
* | ||
* @param Data $data A Data object. | ||
*/ | ||
public function dump(Data $data); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\VarDumper\Dumper; | ||
|
||
/** | ||
* DumperInterface used by Data objects. | ||
* | ||
* @author Nicolas Grekas <p@tchwork.com> | ||
*/ | ||
interface DumperInternalsInterface | ||
{ | ||
/** | ||
* Dumps a scalar value. | ||
* | ||
* @param Cursor $cursor The Cursor position in the dump. | ||
* @param string $type The PHP type of the value being dumped. | ||
* @param scalar $value The scalar value being dumped. | ||
*/ | ||
public function dumpScalar(Cursor $cursor, $type, $value); | ||
|
||
/** | ||
* Dumps a string. | ||
* | ||
* @param Cursor $cursor The Cursor position in the dump. | ||
* @param string $str The string being dumped. | ||
* @param bool $bin Whether $str is UTF-8 or binary encoded. | ||
* @param int $cut The number of characters $str has been cut by. | ||
*/ | ||
public function dumpString(Cursor $cursor, $str, $bin, $cut); | ||
|
||
/** | ||
* Dumps while entering an array. | ||
* | ||
* @param Cursor $cursor The Cursor position in the dump. | ||
* @param int $count The number of items in the original array. | ||
* @param bool $indexed When the array is indexed or associative. | ||
* @param bool $hasChild When the dump of the array has child item. | ||
*/ | ||
public function enterArray(Cursor $cursor, $count, $indexed, $hasChild); | ||
|
||
/** | ||
* Dumps while leaving an array. | ||
* | ||
* @param Cursor $cursor The Cursor position in the dump. | ||
* @param int $count The number of items in the original array. | ||
* @param bool $indexed Whether the array is indexed or associative. | ||
* @param bool $hasChild When the dump of the array has child item. | ||
* @param int $cut The number of items the array has been cut by. | ||
*/ | ||
public function leaveArray(Cursor $cursor, $count, $indexed, $hasChild, $cut); | ||
|
||
/** | ||
* Dumps while entering an object. | ||
* | ||
* @param Cursor $cursor The Cursor position in the dump. | ||
* @param string $class The class of the object. | ||
* @param bool $hasChild When the dump of the object has child item. | ||
*/ | ||
public function enterObject(Cursor $cursor, $class, $hasChild); | ||
|
||
/** | ||
* Dumps while leaving an object. | ||
* | ||
* @param Cursor $cursor The Cursor position in the dump. | ||
* @param string $class The class of the object. | ||
* @param bool $hasChild When the dump of the object has child item. | ||
* @param int $cut The number of items the object has been cut by. | ||
*/ | ||
public function leaveObject(Cursor $cursor, $class, $hasChild, $cut); | ||
|
||
/** | ||
* Dumps while entering a resource. | ||
* | ||
* @param Cursor $cursor The Cursor position in the dump. | ||
* @param string $res The resource type. | ||
* @param bool $hasChild When the dump of the resource has child item. | ||
*/ | ||
public function enterResource(Cursor $cursor, $res, $hasChild); | ||
|
||
/** | ||
* Dumps while leaving a resource. | ||
* | ||
* @param Cursor $cursor The Cursor position in the dump. | ||
* @param string $res The resource type. | ||
* @param bool $hasChild When the dump of the resource has child item. | ||
* @param int $cut The number of items the resource has been cut by. | ||
*/ | ||
public function leaveResource(Cursor $cursor, $res, $hasChild, $cut); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why
CP1252
here ?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CP1252 is a better ISO-8859-1 (in fact, HTML5 recommends auto swapping ISO-8859-1 with CP1252).