105 lines
3.3 KiB
PHP
105 lines
3.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
/**
|
|
* This file is part of Hyperf.
|
|
*
|
|
* @link https://www.hyperf.io
|
|
* @document https://hyperf.wiki
|
|
* @contact group@hyperf.io
|
|
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
|
*/
|
|
namespace Hyperf\Utils\Serializer;
|
|
|
|
use Doctrine\Instantiator\Instantiator;
|
|
use Hyperf\Di\ReflectionManager;
|
|
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
|
|
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
|
|
|
class ExceptionNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface
|
|
{
|
|
/**
|
|
* @var null|Instantiator
|
|
*/
|
|
protected $instantiator;
|
|
|
|
public function denormalize($data, string $class, string $format = null, array $context = [])
|
|
{
|
|
if (is_string($data)) {
|
|
$ex = unserialize($data);
|
|
if ($ex instanceof \Throwable) {
|
|
return $ex;
|
|
}
|
|
|
|
// Retry handle it if the exception not instanceof \Throwable.
|
|
$data = $ex;
|
|
}
|
|
if (is_array($data) && isset($data['message'], $data['code'])) {
|
|
try {
|
|
$exception = $this->getInstantiator()->instantiate($class);
|
|
foreach (['code', 'message', 'file', 'line'] as $attribute) {
|
|
if (isset($data[$attribute])) {
|
|
$property = ReflectionManager::reflectProperty($class, $attribute);
|
|
$property->setAccessible(true);
|
|
$property->setValue($exception, $data[$attribute]);
|
|
}
|
|
}
|
|
return $exception;
|
|
} catch (\ReflectionException $e) {
|
|
return new \RuntimeException(sprintf(
|
|
'Bad data %s: %s',
|
|
$data['class'],
|
|
$data['message']
|
|
), $data['code']);
|
|
} catch (\TypeError $e) {
|
|
return new \RuntimeException(sprintf(
|
|
'Uncaught data %s: %s',
|
|
$data['class'],
|
|
$data['message']
|
|
), $data['code']);
|
|
}
|
|
}
|
|
|
|
return new \RuntimeException('Bad data data: ' . json_encode($data));
|
|
}
|
|
|
|
public function supportsDenormalization($data, $type, $format = null)
|
|
{
|
|
return class_exists($type) && is_a($type, \Throwable::class, true);
|
|
}
|
|
|
|
public function normalize($object, string $format = null, array $context = [])
|
|
{
|
|
if ($object instanceof \Serializable) {
|
|
return serialize($object);
|
|
}
|
|
/* @var \Throwable $object */
|
|
return [
|
|
'message' => $object->getMessage(),
|
|
'code' => $object->getCode(),
|
|
'file' => $object->getFile(),
|
|
'line' => $object->getLine(),
|
|
];
|
|
}
|
|
|
|
public function supportsNormalization($data, string $format = null)
|
|
{
|
|
return $data instanceof \Throwable;
|
|
}
|
|
|
|
public function hasCacheableSupportsMethod(): bool
|
|
{
|
|
return \get_class($this) === __CLASS__;
|
|
}
|
|
|
|
protected function getInstantiator(): Instantiator
|
|
{
|
|
if ($this->instantiator instanceof Instantiator) {
|
|
return $this->instantiator;
|
|
}
|
|
|
|
return $this->instantiator = new Instantiator();
|
|
}
|
|
}
|