10000 feature #28422 [VarExporter] throw component-specific exceptions (nic… · symfony/symfony@deae538 · GitHub
[go: up one dir, main page]

Skip to content

Commit deae538

Browse files
feature #28422 [VarExporter] throw component-specific exceptions (nicolas-grekas)
This PR was merged into the 4.2-dev branch. Discussion ---------- [VarExporter] throw component-specific exceptions | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - This makes "serializing/unserializing" with the component diverge a bit from native serialize/unserialize (wich can throw plain "Exception" instances), but I think we should still do it. Commits ------- 2c44492 [VarExporter] throw component-specific exceptions
2 parents ed5ddf9 + 2c44492 commit deae538

File tree

8 files changed

+81
-15
lines changed

8 files changed

+81
-15
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\VarExporter\Exception;
13+
14+
class ClassNotFoundException extends \Exception implements ExceptionInterface
15+
{
16+
public function __construct(string $class, \Throwable $previous = null)
17+
{
18+
parent::__construct(sprintf('Class "%s" not found.', $class), 0, $previous);
19+
}
20+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\VarExporter\Exception;
13+
14+
interface ExceptionInterface extends \Throwable
15+
{
16+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\VarExporter\Exception;
13+
14+
class NotInstantiableTypeException extends \Exception implements ExceptionInterface
15+
{
16+
public function __construct(string $type)
17+ {
18+
parent::__construct(sprintf('Type "%s" is not instantiable.', $type));
19+
}
20+
}

src/Symfony/Component/VarExporter/Internal/Exporter.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\VarExporter\Internal;
1313

14+
use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
15+
1416
/**
1517
* @author Nicolas Grekas <p@tchwork.com>
1618
*
@@ -31,14 +33,14 @@ class Exporter
3133
*
3234
* @return int
3335
*
34-
* @throws \Exception When a value cannot be serialized
36+
* @throws NotInstantiableTypeException When a value cannot be serialized
3537
*/
3638
public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic)
3739
{
3840
$refs = $values;
3941
foreach ($values as $k => $value) {
4042
if (\is_resource($value)) {
41-
throw new \Exception(sprintf("Serialization of '%s' resource is not allowed", \get_resource_type($value)));
43+
throw new NotInstantiableTypeException(\get_resource_type($value).' resource');
4244
}
4345
$refs[$k] = $objectsPool;
4446

@@ -77,9 +79,12 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
7779
$arrayValue = (array) $value;
7880

7981
if (!isset(Registry::$reflectors[$class])) {
80-
// Might throw Exception("Serialization of '...' is not allowed")
8182
Registry::getClassReflector($class);
82 F438 -
serialize(Registry::$prototypes[$class]);
83+
try {
84+
serialize(Registry::$prototypes[$class]);
85+
} catch (\Exception $e) {
86+
throw new NotInstantiableTypeException($class, $e);
87+
}
8388
if (\method_exists($class, '__sleep')) {
8489
Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]);
8590
}

src/Symfony/Component/VarExporter/Internal/Registry.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
namespace Symfony\Component\VarExporter\Internal;
1313

14+
use Symfony\Component\VarExporter\Exception\ClassNotFoundException;
15+
use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
16+
1417
/**
1518
* @author Nicolas Grekas <p@tchwork.com>
1619
*
@@ -37,9 +40,7 @@ public static function unserialize($objects, $serializables)
3740

3841
try {
3942
foreach ($serializables as $k => $v) {
40-
if (false === $objects[$k] = unserialize($v)) {
41-
throw new \Exception(error_get_last()['message'] ?? 'unserialize(): unknown error');
42-
}
43+
$objects[$k] = unserialize($v);
4344
}
4445
} finally {
4546
ini_set('unserialize_callback_func', $unserializeCallback);
@@ -64,6 +65,9 @@ public static function f($class)
6465

6566
public static function getClassReflector($class, $instantiableWithoutConstructor = false, $cloneable = null)
6667
{
68+
if (!\class_exists($class)) {
69+
throw new ClassNotFoundException($class);
70+
}
6771
$reflector = new \ReflectionClass($class);
6872

6973
if (self::$instantiableWithoutConstructor[$class] = $instantiableWithoutConstructor || !$reflector->isFinal()) {
@@ -77,14 +81,14 @@ public static function getClassReflector($class, $instantiableWithoutConstructor
7781
if ('C:' === $proto && !$reflector->getMethod('unserialize')->isInternal()) {
7882
$proto = null;
7983
} elseif (false === $proto = @unserialize($proto.\strlen($class).':"'.$class.'":0:{}')) {
80-
throw new \Exception(sprintf("Serialization of '%s' is not allowed", $class));
84+
throw new NotInstantiableTypeException($class);
8185
}
8286
}
8387
}
8488

8589
if (null === self::$cloneable[$class] = $cloneable) {
8690
if (($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) && (!$proto instanceof \Serializable && !\method_exists($proto, '__wakeup'))) {
87-
throw new \Exception(sprintf("Serialization of '%s' is not allowed", $class));
91+
throw new NotInstantiableTypeException($class);
8892
}
8993

9094
self::$cloneable[$class] = $reflector->isCloneable() && !$reflector->hasMethod('__clone');

src/Symfony/Component/VarExporter/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ It also provides a few improvements over `var_export()`/`serialize()`:
1616

1717
* the output is PSR-2 compatible;
1818
* the output can be re-indented without messing up with `\r` or `\n` in the data
19-
* missing classes throw a `ReflectionException` instead of being unserialized to
19+
* missing classes throw a `ClassNotFoundException` instead of being unserialized to
2020
`PHP_Incomplete_Class` objects;
2121
* references involving `SplObjectStorage`, `ArrayObject` or `ArrayIterator`
2222
instances are preserved;

src/Symfony/Component/VarExporter/Tests/VarExporterTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ class VarExporterTest extends TestCase
2121
use VarDumperTestTrait;
2222

2323
/**
24-
* @expectedException \ReflectionException
25-
* @expectedExceptionMessage Class SomeNotExistingClass does not exist
24+
* @expectedException \Symfony\Component\VarExporter\Exception\ClassNotFoundException
25+
* @expectedExceptionMessage Class "SomeNotExistingClass" not found.
2626
*/
2727
public function testPhpIncompleteClassesAreForbidden()
2828
{
@@ -36,8 +36,8 @@ public function testPhpIncompleteClassesAreForbidden()
3636

3737
/**
3838
* @dataProvider provideFailingSerialization
39-
* @expectedException \Exception
40-
* @expectedExceptionMessageRegexp Serialization of '.*' is not allowed
39+
* @expectedException \Symfony\Component\VarExporter\Exception\NotInstantiableTypeException
40+
* @expectedExceptionMessageRegexp Type ".*" is not instantiable.
4141
*/
4242
public function testFailingSerialization($value)
4343
{

src/Symfony/Component/VarExporter/VarExporter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\VarExporter;
1313

14+
use Symfony\Component\VarExporter\Exception\ExceptionInterface;
1415
use Symfony\Component\VarExporter\Internal\Exporter;
1516
use Symfony\Component\VarExporter\Internal\Hydrator;
1617
use Symfony\Component\VarExporter\Internal\Registry;
@@ -36,7 +37,7 @@ final class VarExporter
3637
*
3738
* @return string The value exported as PHP code
3839
*
39-
* @throws \Exception When the provided value cannot be serialized
40+
* @throws ExceptionInterface When the provided value cannot be serialized
4041
*/
4142
public static function export($value, bool &$isStaticValue = null): string
4243
{

0 commit comments

Comments
 (0)
0