Unverified Commit fafac8da authored by Sergei Morozov's avatar Sergei Morozov Committed by GitHub

Merge pull request #3180 from Majkl578/replace-common-debug

Import simplified version of Common\Util\Debug for var dumping purposes
parents 8338e8a4 30d377aa
...@@ -19,14 +19,13 @@ ...@@ -19,14 +19,13 @@
namespace Doctrine\DBAL\Tools\Console\Command; namespace Doctrine\DBAL\Tools\Console\Command;
use Doctrine\DBAL\Tools\Dumper;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use function is_numeric; use function is_numeric;
use function ob_get_clean;
use function ob_start;
use function stripos; use function stripos;
/** /**
...@@ -84,10 +83,6 @@ EOT ...@@ -84,10 +83,6 @@ EOT
$resultSet = $conn->executeUpdate($sql); $resultSet = $conn->executeUpdate($sql);
} }
ob_start(); $output->write(Dumper::dump($resultSet, (int) $depth));
\Doctrine\Common\Util\Debug::dump($resultSet, (int) $depth);
$message = ob_get_clean();
$output->write($message);
} }
} }
<?php
namespace Doctrine\DBAL\Tools;
use ArrayIterator;
use ArrayObject;
use DateTimeInterface;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Persistence\Proxy;
use stdClass;
use function array_keys;
use function class_exists;
use function count;
use function end;
use function explode;
use function extension_loaded;
use function get_class;
use function html_entity_decode;
use function ini_get;
use function ini_set;
use function is_array;
use function is_object;
use function ob_get_clean;
use function ob_start;
use function strip_tags;
use function strrpos;
use function substr;
use function var_dump;
/**
* Static class used to dump the variable to be used on output.
* Simplified port of Util\Debug from doctrine/common.
*
* @internal
*/
final class Dumper
{
/**
* Private constructor (prevents instantiation).
*/
private function __construct()
{
}
/**
* Returns a dump of the public, protected and private properties of $var.
*
* @link https://xdebug.org/
*
* @param mixed $var The variable to dump.
* @param int $maxDepth The maximum nesting level for object properties.
*/
public static function dump($var, int $maxDepth = 2) : string
{
$html = ini_get('html_errors');
if ($html !== true) {
ini_set('html_errors', true);
}
if (extension_loaded('xdebug')) {
ini_set('xdebug.var_display_max_depth', $maxDepth);
}
$var = self::export($var, $maxDepth);
ob_start();
var_dump($var);
try {
return strip_tags(html_entity_decode(ob_get_clean()));
} finally {
ini_set('html_errors', $html);
}
}
/**
* @param mixed $var
*
* @return mixed
*/
public static function export($var, int $maxDepth)
{
$return = null;
$isObj = is_object($var);
if ($var instanceof Collection) {
$var = $var->toArray();
}
if ($maxDepth === 0) {
return is_object($var) ? get_class($var)
: (is_array($var) ? 'Array(' . count($var) . ')' : $var);
}
if (is_array($var)) {
$return = [];
foreach ($var as $k => $v) {
$return[$k] = self::export($v, $maxDepth - 1);
}
return $return;
}
if (! $isObj) {
return $var;
}
$return = new stdClass();
if ($var instanceof DateTimeInterface) {
$return->__CLASS__ = get_class($var);
$return->date = $var->format('c');
$return->timezone = $var->getTimezone()->getName();
return $return;
}
$return->__CLASS__ = self::getClass($var);
if ($var instanceof Proxy) {
$return->__IS_PROXY__ = true;
$return->__PROXY_INITIALIZED__ = $var->__isInitialized();
}
if ($var instanceof ArrayObject || $var instanceof ArrayIterator) {
$return->__STORAGE__ = self::export($var->getArrayCopy(), $maxDepth - 1);
}
return self::fillReturnWithClassAttributes($var, $return, $maxDepth);
}
/**
* Fill the $return variable with class attributes
* Based on obj2array function from {@see https://secure.php.net/manual/en/function.get-object-vars.php#47075}
*
* @param object $var
*
* @return mixed
*/
private static function fillReturnWithClassAttributes($var, stdClass $return, int $maxDepth)
{
$clone = (array) $var;
foreach (array_keys($clone) as $key) {
$aux = explode("\0", $key);
$name = end($aux);
if ($aux[0] === '') {
$name .= ':' . ($aux[1] === '*' ? 'protected' : $aux[1] . ':private');
}
$return->$name = self::export($clone[$key], $maxDepth - 1);
;
}
return $return;
}
/**
* @param object $object
*/
private static function getClass($object) : string
{
$class = get_class($object);
if (! class_exists(Proxy::class)) {
return $class;
}
$pos = strrpos($class, '\\' . Proxy::MARKER . '\\');
if ($pos === false) {
return $class;
}
return substr($class, $pos + Proxy::MARKER_LENGTH + 2);
}
}
...@@ -31,4 +31,8 @@ ...@@ -31,4 +31,8 @@
<rule ref="Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase"> <rule ref="Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase">
<exclude-pattern>lib/Doctrine/DBAL/Events.php</exclude-pattern> <exclude-pattern>lib/Doctrine/DBAL/Events.php</exclude-pattern>
</rule> </rule>
<rule ref="SlevomatCodingStandard.Classes.UnusedPrivateElements.UnusedProperty">
<exclude-pattern>tests/Doctrine/Tests/DBAL/Tools/TestAsset/*</exclude-pattern>
</rule>
</ruleset> </ruleset>
<?php
namespace Doctrine\Tests\DBAL\Tools;
use ArrayIterator;
use ArrayObject;
use DateTime;
use DateTimeImmutable;
use DateTimeZone;
use Doctrine\DBAL\Tools\Dumper;
use Doctrine\Tests\DbalTestCase;
use function print_r;
use function strpos;
use function substr;
class DumperTest extends DbalTestCase
{
public function testExportObject()
{
$obj = new \stdClass();
$obj->foo = 'bar';
$obj->bar = 1234;
$var = Dumper::export($obj, 2);
self::assertEquals('stdClass', $var->__CLASS__);
}
public function testExportObjectWithReference()
{
$foo = 'bar';
$bar = ['foo' => & $foo];
$baz = (object) $bar;
$var = Dumper::export($baz, 2);
$baz->foo = 'tab';
self::assertEquals('bar', $var->foo);
self::assertEquals('tab', $bar['foo']);
}
public function testExportArray()
{
$array = ['a' => 'b', 'b' => ['c', 'd' => ['e', 'f']]];
$var = Dumper::export($array, 2);
$expected = $array;
$expected['b']['d'] = 'Array(2)';
self::assertEquals($expected, $var);
}
public function testExportDateTime()
{
$obj = new DateTime('2010-10-10 10:10:10', new DateTimeZone('UTC'));
$var = Dumper::export($obj, 2);
self::assertEquals('DateTime', $var->__CLASS__);
self::assertEquals('2010-10-10T10:10:10+00:00', $var->date);
}
public function testExportDateTimeImmutable()
{
$obj = new DateTimeImmutable('2010-10-10 10:10:10', new DateTimeZone('UTC'));
$var = Dumper::export($obj, 2);
self::assertEquals('DateTimeImmutable', $var->__CLASS__);
self::assertEquals('2010-10-10T10:10:10+00:00', $var->date);
}
public function testExportDateTimeZone()
{
$obj = new DateTimeImmutable('2010-10-10 12:34:56', new DateTimeZone('Europe/Rome'));
$var = Dumper::export($obj, 2);
self::assertEquals('DateTimeImmutable', $var->__CLASS__);
self::assertEquals('2010-10-10T12:34:56+02:00', $var->date);
}
public function testExportArrayTraversable()
{
$obj = new ArrayObject(['foobar']);
$var = Dumper::export($obj, 2);
self::assertContains('foobar', $var->__STORAGE__);
$it = new ArrayIterator(['foobar']);
$var = Dumper::export($it, 5);
self::assertContains('foobar', $var->__STORAGE__);
}
/**
* @param string[] $expected
*
* @dataProvider provideAttributesCases
*/
public function testExportParentAttributes(TestAsset\ParentClass $class, array $expected)
{
$print_r_class = print_r($class, true);
$print_r_expected = print_r($expected, true);
$print_r_class = substr($print_r_class, strpos($print_r_class, '('));
$print_r_expected = substr($print_r_expected, strpos($print_r_expected, '('));
self::assertSame($print_r_class, $print_r_expected);
$var = Dumper::export($class, 3);
$var = (array) $var;
unset($var['__CLASS__']);
self::assertSame($expected, $var);
}
public function provideAttributesCases()
{
return [
'different-attributes' => [
new TestAsset\ChildClass(),
[
'childPublicAttribute' => 4,
'childProtectedAttribute:protected' => 5,
'childPrivateAttribute:Doctrine\Tests\DBAL\Tools\TestAsset\ChildClass:private' => 6,
'parentPublicAttribute' => 1,
'parentProtectedAttribute:protected' => 2,
'parentPrivateAttribute:Doctrine\Tests\DBAL\Tools\TestAsset\ParentClass:private' => 3,
],
],
'same-attributes' => [
new TestAsset\ChildWithSameAttributesClass(),
[
'parentPublicAttribute' => 4,
'parentProtectedAttribute:protected' => 5,
'parentPrivateAttribute:Doctrine\Tests\DBAL\Tools\TestAsset\ChildWithSameAttributesClass:private' => 6,
'parentPrivateAttribute:Doctrine\Tests\DBAL\Tools\TestAsset\ParentClass:private' => 3,
],
],
];
}
}
<?php
namespace Doctrine\Tests\DBAL\Tools\TestAsset;
final class ChildClass extends ParentClass
{
/** @var int */
public $childPublicAttribute = 4;
/** @var int */
protected $childProtectedAttribute = 5;
/** @var int */
private $childPrivateAttribute = 6;
}
<?php
namespace Doctrine\Tests\DBAL\Tools\TestAsset;
final class ChildWithSameAttributesClass extends ParentClass
{
/** @var int */
public $parentPublicAttribute = 4;
/** @var int */
protected $parentProtectedAttribute = 5;
/** @var int */
private $parentPrivateAttribute = 6;
}
<?php
namespace Doctrine\Tests\DBAL\Tools\TestAsset;
abstract class ParentClass
{
/** @var int */
public $parentPublicAttribute = 1;
/** @var int */
protected $parentProtectedAttribute = 2;
/** @var int */
private $parentPrivateAttribute = 3;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment