Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b959d85

Browse files
feature #28218 Improve support for anonymous classes (nicolas-grekas)
This PR was merged into the 4.2-dev branch. Discussion ---------- Improve support for anonymous classes | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Before: ![image](https://user-images.githubusercontent.com/243674/44276933-5c522600-a249-11e8-8bcc-6d55c9fa5a5e.png) After: ![image](https://user-images.githubusercontent.com/243674/44276912-4cd2dd00-a249-11e8-943f-b6b0d0eb8908.png) Same in other places, e.g. Console failures. Commits ------- e41ced2 Improve support for anonymous classes
2 parents 7714631 + e41ced2 commit b959d85

File tree

11 files changed

+180
-20
lines changed

11 files changed

+180
-20
lines changed

src/Symfony/Component/Console/Application.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,12 +753,20 @@ protected function doRenderException(\Exception $e, OutputInterface $output)
753753
do {
754754
$message = trim($e->getMessage());
755755
if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
756-
$title = sprintf(' [%s%s] ', \get_class($e), 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : '');
756+
$class = \get_class($e);
757+
$class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
758+
$title = sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : '');
757759
$len = Helper::strlen($title);
758760
} else {
759761
$len = 0;
760762
}
761763

764+
if (false !== strpos($message, "class@anonymous\0")) {
765+
$message = preg_replace_callback('/class@anonymous\x00.*?\.php0x?[0-9a-fA-F]++/', function ($m) {
766+
return \class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0];
767+
}, $message);
768+
}
769+
762770
$width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : PHP_INT_MAX;
763771
$lines = array();
764772
foreach ('' !== $message ? preg_split('/\r?\n/', $message) : array() as $line) {

src/Symfony/Component/Console/Tests/ApplicationTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,31 @@ public function testRenderExceptionLineBreaks()
824824
$this->assertStringMatchesFormatFile(self::$fixturesPath.'/application_renderexception_linebreaks.txt', $tester->getDisplay(true), '->renderException() keep multiple line breaks');
825825
}
826826

827+
public function testRenderAnonymousException()
828+
{
829+
$application = new Application();
830+
$application->setAutoExit(false);
831+
$application->register('foo')->setCode(function () {
832+
throw new class('') extends \InvalidArgumentException {
833+
};
834+
});
835+
$tester = new ApplicationTester($application);
836+
837+
$tester->run(array('command' => 'foo'), array('decorated' => false));
838+
$this->assertContains('[InvalidArgumentException@anonymous]', $tester->getDisplay(true));
839+
840+
$application = new Application();
841+
$application->setAutoExit(false);
842+
$application->register('foo')->setCode(function () {
843+
throw new \InvalidArgumentException(sprintf('Dummy type "%s" is invalid.', \get_class(new class() {
844+
})));
845+
});
846+
$tester = new ApplicationTester($application);
847+
848+
$tester->run(array('command' => 'foo'), array('decorated' => false));
849+
$this->assertContains('Dummy type "@anonymous" is invalid.', $tester->getDisplay(true));
850+
}
851+
827852
public function testRun()
828853
{
829854
$application = new Application();

src/Symfony/Component/Debug/ErrorHandler.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Psr\Log\LogLevel;
1616
use Symfony\Component\Debug\Exception\FatalErrorException;
1717
use Symfony\Component\Debug\Exception\FatalThrowableError;
18+
use Symfony\Component\Debug\Exception\FlattenException;
1819
use Symfony\Component\Debug\Exception\OutOfMemoryException;
1920
use Symfony\Component\Debug\Exception\SilencedErrorContext;
2021
use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
@@ -405,7 +406,11 @@ public function handleError($type, $message, $file, $line)
405406
$context = $e;
406407
}
407408

408-
$logMessage = $this->levels[$type].': '.$message;
409+
if (false !== strpos($message, "class@anonymous\0")) {
410+
$logMessage = $this->levels[$type].': '.(new FlattenException())->setMessage($message)->getMessage();
411+
} else {
412+
$logMessage = $this->levels[$type].': '.$message;
413+
}
409414

410415
if (null !== self::$toStringException) {
411416
$errorAsException = self::$toStringException;
@@ -518,21 +523,24 @@ public function handleException($exception, array $error = null)
518523
$handlerException = null;
519524

520525
if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
526+
if (false !== strpos($message = $exception->getMessage(), "class@anonymous\0")) {
527+
$message = (new FlattenException())->setMessage($message)->getMessage();
528+
}
521529
if ($exception instanceof FatalErrorException) {
522530
if ($exception instanceof FatalThrowableError) {
523531
$error = array(
524532
'type' => $type,
525-
'message' => $message = $exception->getMessage(),
533+
'message' => $message,
526534
'file' => $exception->getFile(),
527535
'line' => $exception->getLine(),
528536
);
529537
} else {
530-
$message = 'Fatal '.$exception->getMessage();
538+
$message = 'Fatal '.$message;
531539
}
532540
} elseif ($exception instanceof \ErrorException) {
533-
$message = 'Uncaught '.$exception->getMessage();
541+
$message = 'Uncaught '.$message;
534542
} else {
535-
$message = 'Uncaught Exception: '.$exception->getMessage();
543+
$message = 'Uncaught Exception: '.$message;
536544
}
537545
}
538546
if ($this->loggedErrors & $type) {

src/Symfony/Component/Debug/Exception/FlattenException.php

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,79 +90,125 @@ public function getStatusCode()
9090
return $this->statusCode;
9191
}
9292

93+
/**
94+
* @return $this
95+
*/
9396
public function setStatusCode($code)
9497
{
9598
$this->statusCode = $code;
99+
100+
return $this;
96101
}
97102

98103
public function getHeaders()
99104
{
100105
return $this->headers;
101106
}
102107

108+
/**
109+
* @return $this
110+
*/
103111
public function setHeaders(array $headers)
104112
{
105113
$this->headers = $headers;
114+
115+
return $this;
106116
}
107117

108118
public function getClass()
109119
{
110120
return $this->class;
111121
}
112122

123+
/**
124+
* @return $this
125+
*/
113126
public function setClass($class)
114127
{
115-
$this->class = $class;
128+
$this->class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
129+
130+
return $this;
116131
}
117132

118133
public function getFile()
119134
{
120135
return $this->file;
121136
}
122137

138+
/**
139+
* @return $this
140+
*/
123141
public function setFile($file)
124142
{
125143
$this->file = $file;
144+
145+
return $this;
126146
}
127147

128148
public function getLine()
129149
{
130150
return $this->line;
131151
}
132152

153+
/**
154+
* @return $this
155+
*/
133156
public function setLine($line)
134157
{
135158
$this->line = $line;
159+
160+
return $this;
136161
}
137162

138163
public function getMessage()
139164
{
140165
return $this->message;
141166
}
142167

168+
/**
169+
* @return $this
170+
*/
143171
public function setMessage($message)
144172
{
173+
if (false !== strpos($message, "class@anonymous\0")) {
174+
$message = preg_replace_callback('/class@anonymous\x00.*?\.php0x?[0-9a-fA-F]++/', function ($m) {
175+
return \class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0];
176+
}, $message);
177+
}
178+
145179
$this->message = $message;
180+
181+
return $this;
146182
}
147183

148184
public function getCode()
149185
{
150186
return $this->code;
151187
}
152188

189+
/**
190+
* @return $this
191+
*/
153192
public function setCode($code)
154193
{
155194
$this->code = $code;
195+
196+
return $this;
156197
}
157198

158199
public function getPrevious()
159200
{
160201
return $this->previous;
161202
}
162203

204+
/**
205+
* @return $this
206+
*/
163207
public function setPrevious(self $previous)
164208
{
165209
$this->previous = $previous;
210+
211+
return $this;
166212
}
167213

168214
public function getAllPrevious()
@@ -191,11 +237,14 @@ public function setTraceFromException(\Exception $exception)
191237
$this->setTraceFromThrowable($exception);
192238
}
193239

194-
public function setTraceFromThrowable(\Throwable $throwable): void
240+
public function setTraceFromThrowable(\Throwable $throwable)
195241
{
196-
$this->setTrace($throwable->getTrace(), $throwable->getFile(), $throwable->getLine());
242+
return $this->setTrace($throwable->getTrace(), $throwable->getFile(), $throwable->getLine());
197243
}
198244

245+
/**
246+
* @return $this
247+
*/
199248
public function setTrace($trace, $file, $line)
200249
{
201250
$this->trace = array();
@@ -229,6 +278,8 @@ public function setTrace($trace, $file, $line)
229278
'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : array(),
230279
);
231280
}
281+
282+
return $this;
232283
}
233284

234285
private function flattenArgs($args, $level = 0, &$count = 0)

src/Symfony/Component/Debug/ExceptionHandler.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ public function getContent(FlattenException $exception)
253253
} catch (\Exception $e) {
254254
// something nasty happened and we cannot throw an exception anymore
255255
if ($this->debug) {
256-
$title = sprintf('Exception thrown when handling an exception (%s: %s)', \get_class($e), $this->escapeHtml($e->getMessage()));
256+
$e = FlattenException::create($e);
257+
$title = sprintf('Exception thrown when handling an exception (%s: %s)', $e->getClass(), $this->escapeHtml($e->getMessage()));
257258
} else {
258259
$title = 'Whoops, looks like something went wrong.';
259260
}

src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,19 @@ public function testTooBigArray()
333333
$this->assertNotContains('*value1*', $serializeTrace);
334334
}
335335

336+
public function testAnonymousClass()
337+
{
338+
$flattened = FlattenException::create(new class() extends \RuntimeException {
339+
});
340+
341+
$this->assertSame('RuntimeException@anonymous', $flattened->getClass());
342+
343+
$flattened = FlattenException::create(new \Exception(sprintf('Class "%s" blah.', \get_class(new class() extends \RuntimeException {
344+
}))));
345+
346+
$this->assertSame('Class "RuntimeException@anonymous" blah.', $flattened->getMessage());
347+
}
348+
336349
private function createException($foo)
337350
{
338351
return new \Exception();

src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ public function __construct($controller, LoggerInterface $logger = null, $debug
5050

5151
public function logKernelException(GetResponseForExceptionEvent $event)
5252
{
53-
$exception = $event->getException();
53+
$e = FlattenException::create($event->getException());
5454

55-
$this->logException($exception, sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', \get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine()));
55+
$this->logException($event->getException(), sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine()));
5656
}
5757

5858
public function onKernelException(GetResponseForExceptionEvent $event)
@@ -75,7 +75,9 @@ public function onKernelException(GetResponseForExceptionEvent $event)
7575
try {
7676
$response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false);
7777
} catch (\Exception $e) {
78-
$this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', \get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()));
78+
$f = FlattenException::create($e);
79+
80+
$this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), $e->getFile(), $e->getLine()));
7981

8082
$wrapper = $e;
8183

src/Symfony/Component/VarDumper/Caster/ClassStub.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,6 @@ public function __construct(string $identifier, $callable = null)
2828
{
2929
$this->value = $identifier;
3030

31-
if (0 < $i = strrpos($identifier, '\\')) {
32-
$this->attr['ellipsis'] = \strlen($identifier) - $i;
33-
$this->attr['ellipsis-type'] = 'class';
34-
$this->attr['ellipsis-tail'] = 1;
35-
}
36-
3731
try {
3832
if (null !== $callable) {
3933
if ($callable instanceof \Closure) {
@@ -61,6 +55,12 @@ public function __construct(string $identifier, $callable = null)
6155
}
6256
}
6357

58+
if (false !== strpos($identifier, "class@anonymous\0")) {
59+
$this->value = $identifier = preg_replace_callback('/class@anonymous\x00.*?\.php0x?[0-9a-fA-F]++/', function ($m) {
60+
return \class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0];
61+
}, $identifier);
62+
}
63+
6464
if (null !== $callable && $r instanceof \ReflectionFunctionAbstract) {
6565
$s = ReflectionCaster::castFunctionAbstract($r, array(), new Stub(), true);
6666
$s = ReflectionCaster::getSignature($s);
@@ -76,6 +76,12 @@ public function __construct(string $identifier, $callable = null)
7676
}
7777
} catch (\ReflectionException $e) {
7878
return;
79+
} finally {
80+
if (0 < $i = strrpos($identifier, '\\')) {
81+
$this->attr['ellipsis'] = \strlen($identifier) - $i;
82+
$this->attr['ellipsis-type'] = 'class';
83+
$this->attr['ellipsis-tail'] = 1;
84+
}
7985
}
8086

8187
if ($f = $r->getFileName()) {

src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ public static function castThrowingCasterException(ThrowingCasterException $e, a
7171

7272
if (isset($a[$xPrefix.'previous'], $a[$trace]) && $a[$xPrefix.'previous'] instanceof \Exception) {
7373
$b = (array) $a[$xPrefix.'previous'];
74-
self::traceUnshift($b[$xPrefix.'trace'], \get_class($a[$xPrefix.'previous']), $b[$prefix.'file'], $b[$prefix.'line']);
74+
$class = \get_class($a[$xPrefix.'previous']);
75+
$class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
76+
self::traceUnshift($b[$xPrefix.'trace'], $class, $b[$prefix.'file'], $b[$prefix.'line']);
7577
$a[$trace] = new TraceStub($b[$xPrefix.'trace'], false, 0, -\count($a[$trace]->value));
7678
}
7779

@@ -279,6 +281,12 @@ private static function filterExceptionArray($xClass, array $a, $xPrefix, $filte
279281
}
280282
unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']);
281283

284+
if (isset($a[Caster::PREFIX_PROTECTED.'message']) && false !== strpos($a[Caster::PREFIX_PROTECTED.'message'], "class@anonymous\0")) {
285+
$a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/class@anonymous\x00.*?\.php0x?[0-9a-fA-F]++/', function ($m) {
286+
return \class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0];
287+
}, $a[Caster::PREFIX_PROTECTED.'message']);
288+
}
289+
282290
if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) {
283291
$a[Caster::PREFIX_PROTECTED.'file'] = new LinkStub($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']);
284292
}

src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,23 @@ public function testExcludeVerbosity()
223223
#file: "%sExceptionCasterTest.php"
224224
#line: 28
225225
}
226+
EODUMP;
227+
228+
$this->assertDumpMatchesFormat($expectedDump, $e, Caster::EXCLUDE_VERBOSE);
229+
}
230+
231+
public function testAnonymous()
232+
{
233+
$e = new \Exception(sprintf('Boo "%s" ba.', \get_class(new class('Foo') extends \Exception {
234+
})));
235+
236+
$expectedDump = <<<'EODUMP'
237+
Exception {
238+
#message: "Boo "Exception@anonymous" ba."
239+
#code: 0
240+
#file: "%sExceptionCasterTest.php"
241+
#line: %d
242+
}
226243
EODUMP;
227244

228245
$this->assertDumpMatchesFormat($expectedDump, $e, Caster::EXCLUDE_VERBOSE);

0 commit comments

Comments
 (0)