SourceExceptionFactory.php 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. namespace PhpCsFixer\Error;
  13. /**
  14. * @internal
  15. */
  16. final class SourceExceptionFactory
  17. {
  18. /**
  19. * @param array{class: class-string<\Throwable>, message: string, code: int, file: string, line: int} $error
  20. */
  21. public static function fromArray(array $error): \Throwable
  22. {
  23. $exceptionClass = $error['class'];
  24. try {
  25. $exception = new $exceptionClass($error['message'], $error['code']);
  26. if (
  27. $exception->getMessage() !== $error['message']
  28. || $exception->getCode() !== $error['code']
  29. ) {
  30. throw new \RuntimeException('Failed to create exception from array. Message and code are not the same.');
  31. }
  32. } catch (\Throwable $e) {
  33. $exception = new \RuntimeException(
  34. sprintf('[%s] %s', $exceptionClass, $error['message']),
  35. $error['code']
  36. );
  37. }
  38. try {
  39. $exceptionReflection = new \ReflectionClass($exception);
  40. foreach (['file', 'line'] as $property) {
  41. $propertyReflection = $exceptionReflection->getProperty($property);
  42. $propertyReflection->setAccessible(true);
  43. $propertyReflection->setValue($exception, $error[$property]);
  44. $propertyReflection->setAccessible(false);
  45. }
  46. } catch (\Throwable $reflectionException) {
  47. // Ignore if we were not able to set file/line properties. In most cases it should be fine,
  48. // we just need to make sure nothing is broken when we recreate errors from raw data passed from worker.
  49. }
  50. return $exception;
  51. }
  52. }