vendor/symfony/var-exporter/Internal/LazyObjectState.php line 100

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\VarExporter\Internal;
  11. use Symfony\Component\VarExporter\Hydrator as PublicHydrator;
  12. /**
  13. * Keeps the state of lazy objects.
  14. *
  15. * As a micro-optimization, this class uses no type declarations.
  16. *
  17. * @internal
  18. */
  19. class LazyObjectState
  20. {
  21. public const STATUS_UNINITIALIZED_FULL = 1;
  22. public const STATUS_UNINITIALIZED_PARTIAL = 2;
  23. public const STATUS_INITIALIZED_FULL = 3;
  24. public const STATUS_INITIALIZED_PARTIAL = 4;
  25. /**
  26. * @var array<string, true>
  27. */
  28. public readonly array $skippedProperties;
  29. /**
  30. * @var self::STATUS_*
  31. */
  32. public int $status = 0;
  33. public object $realInstance;
  34. public function __construct(public readonly \Closure|array $initializer, $skippedProperties = [])
  35. {
  36. $this->skippedProperties = $skippedProperties;
  37. $this->status = \is_array($initializer) ? self::STATUS_UNINITIALIZED_PARTIAL : self::STATUS_UNINITIALIZED_FULL;
  38. }
  39. public function initialize($instance, $propertyName, $propertyScope)
  40. {
  41. if (self::STATUS_INITIALIZED_FULL === $this->status) {
  42. return self::STATUS_INITIALIZED_FULL;
  43. }
  44. if (\is_array($this->initializer)) {
  45. $class = $instance::class;
  46. $propertyScope ??= $class;
  47. $propertyScopes = Hydrator::$propertyScopes[$class];
  48. $propertyScopes[$k = "\0$propertyScope\0$propertyName"] ?? $propertyScopes[$k = "\0*\0$propertyName"] ?? $k = $propertyName;
  49. if ($initializer = $this->initializer[$k] ?? null) {
  50. $value = $initializer(...[$instance, $propertyName, $propertyScope, LazyObjectRegistry::$defaultProperties[$class][$k] ?? null]);
  51. $accessor = LazyObjectRegistry::$classAccessors[$propertyScope] ??= LazyObjectRegistry::getClassAccessors($propertyScope);
  52. $accessor['set']($instance, $propertyName, $value);
  53. return $this->status = self::STATUS_INITIALIZED_PARTIAL;
  54. }
  55. if ($initializer = $this->initializer["\0"] ?? null) {
  56. if (!\is_array($values = $initializer($instance, LazyObjectRegistry::$defaultProperties[$class]))) {
  57. throw new \TypeError(sprintf('The lazy-initializer defined for instance of "%s" must return an array, got "%s".', $class, get_debug_type($values)));
  58. }
  59. $properties = (array) $instance;
  60. foreach ($values as $key => $value) {
  61. if (!\array_key_exists($key, $properties) && [$scope, $name, $readonlyScope] = $propertyScopes[$key] ?? null) {
  62. $scope = $readonlyScope ?? ('*' !== $scope ? $scope : $class);
  63. $accessor = LazyObjectRegistry::$classAccessors[$scope] ??= LazyObjectRegistry::getClassAccessors($scope);
  64. $accessor['set']($instance, $name, $value);
  65. if ($k === $key) {
  66. $this->status = self::STATUS_INITIALIZED_PARTIAL;
  67. }
  68. }
  69. }
  70. }
  71. return $this->status;
  72. }
  73. if (self::STATUS_INITIALIZED_PARTIAL === $this->status) {
  74. return self::STATUS_INITIALIZED_PARTIAL;
  75. }
  76. $this->status = self::STATUS_INITIALIZED_PARTIAL;
  77. try {
  78. if ($defaultProperties = array_diff_key(LazyObjectRegistry::$defaultProperties[$instance::class], $this->skippedProperties)) {
  79. PublicHydrator::hydrate($instance, $defaultProperties);
  80. }
  81. ($this->initializer)($instance);
  82. } catch (\Throwable $e) {
  83. $this->status = self::STATUS_UNINITIALIZED_FULL;
  84. $this->reset($instance);
  85. throw $e;
  86. }
  87. return $this->status = self::STATUS_INITIALIZED_FULL;
  88. }
  89. public function reset($instance): void
  90. {
  91. $class = $instance::class;
  92. $propertyScopes = Hydrator::$propertyScopes[$class] ??= Hydrator::getPropertyScopes($class);
  93. $skippedProperties = $this->skippedProperties;
  94. $properties = (array) $instance;
  95. $onlyProperties = \is_array($this->initializer) ? $this->initializer : null;
  96. foreach ($propertyScopes as $key => [$scope, $name, $readonlyScope]) {
  97. $propertyScopes[$k = "\0$scope\0$name"] ?? $propertyScopes[$k = "\0*\0$name"] ?? $k = $name;
  98. if ($k === $key && (null !== $readonlyScope || !\array_key_exists($k, $properties))) {
  99. $skippedProperties[$k] = true;
  100. }
  101. }
  102. foreach (LazyObjectRegistry::$classResetters[$class] as $reset) {
  103. $reset($instance, $skippedProperties, $onlyProperties);
  104. }
  105. $this->status = self::STATUS_INITIALIZED_FULL === $this->status ? self::STATUS_UNINITIALIZED_FULL : self::STATUS_UNINITIALIZED_PARTIAL;
  106. }
  107. }