DataCollector.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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\HttpKernel\DataCollector;
  11. use Symfony\Component\VarDumper\Caster\CutStub;
  12. use Symfony\Component\VarDumper\Caster\ReflectionCaster;
  13. use Symfony\Component\VarDumper\Cloner\ClonerInterface;
  14. use Symfony\Component\VarDumper\Cloner\Data;
  15. use Symfony\Component\VarDumper\Cloner\Stub;
  16. use Symfony\Component\VarDumper\Cloner\VarCloner;
  17. /**
  18. * DataCollector.
  19. *
  20. * Children of this class must store the collected data in the data property.
  21. *
  22. * @author Fabien Potencier <fabien@symfony.com>
  23. * @author Bernhard Schussek <bschussek@symfony.com>
  24. */
  25. abstract class DataCollector implements DataCollectorInterface
  26. {
  27. protected array|Data $data = [];
  28. private ClonerInterface $cloner;
  29. /**
  30. * Converts the variable into a serializable Data instance.
  31. *
  32. * This array can be displayed in the template using
  33. * the VarDumper component.
  34. */
  35. protected function cloneVar(mixed $var): Data
  36. {
  37. if ($var instanceof Data) {
  38. return $var;
  39. }
  40. if (!isset($this->cloner)) {
  41. $this->cloner = new VarCloner();
  42. $this->cloner->setMaxItems(-1);
  43. $this->cloner->addCasters($this->getCasters());
  44. }
  45. return $this->cloner->cloneVar($var);
  46. }
  47. /**
  48. * @return callable[] The casters to add to the cloner
  49. */
  50. protected function getCasters(): array
  51. {
  52. return [
  53. '*' => function ($v, array $a, Stub $s, $isNested) {
  54. if (!$v instanceof Stub) {
  55. $b = $a;
  56. foreach ($a as $k => $v) {
  57. if (!\is_object($v) || $v instanceof \DateTimeInterface || $v instanceof Stub) {
  58. continue;
  59. }
  60. try {
  61. $a[$k] = $s = new CutStub($v);
  62. if ($b[$k] === $s) {
  63. // we've hit a non-typed reference
  64. $a[$k] = $v;
  65. }
  66. } catch (\TypeError $e) {
  67. // we've hit a typed reference
  68. }
  69. }
  70. }
  71. return $a;
  72. },
  73. ] + ReflectionCaster::UNSET_CLOSURE_FILE_INFO;
  74. }
  75. public function __serialize(): array
  76. {
  77. if (self::class === (new \ReflectionMethod($this, '__sleep'))->class || self::class !== (new \ReflectionMethod($this, '__serialize'))->class) {
  78. return ['data' => $this->data];
  79. }
  80. trigger_deprecation('symfony/http-kernel', '7.4', 'Implementing "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this));
  81. $data = [];
  82. foreach ($this->__sleep() as $key) {
  83. try {
  84. if (($r = new \ReflectionProperty($this, $key))->isInitialized($this)) {
  85. $data[$key] = $r->getValue($this);
  86. }
  87. } catch (\ReflectionException) {
  88. $data[$key] = $this->$key;
  89. }
  90. }
  91. return $data;
  92. }
  93. public function __unserialize(array $data): void
  94. {
  95. if ($wakeup = self::class !== (new \ReflectionMethod($this, '__wakeup'))->class && self::class === (new \ReflectionMethod($this, '__unserialize'))->class) {
  96. trigger_deprecation('symfony/http-kernel', '7.4', 'Implementing "%s::__wakeup()" is deprecated, use "__unserialize()" instead.', get_debug_type($this));
  97. }
  98. if (\in_array(array_keys($data), [['data'], ["\0*\0data"]], true)) {
  99. $this->data = $data['data'] ?? $data["\0*\0data"];
  100. if ($wakeup) {
  101. $this->__wakeup();
  102. }
  103. return;
  104. }
  105. trigger_deprecation('symfony/http-kernel', '7.4', 'Passing more than just key "data" to "%s::__unserialize()" is deprecated, populate properties in "%s::__unserialize()" instead.', self::class, get_debug_type($this));
  106. \Closure::bind(function ($data) use ($wakeup) {
  107. foreach ($data as $key => $value) {
  108. $this->{("\0" === $key[0] ?? '') ? substr($key, 1 + strrpos($key, "\0")) : $key} = $value;
  109. }
  110. if ($wakeup) {
  111. $this->__wakeup();
  112. }
  113. }, $this, static::class)($data);
  114. }
  115. /**
  116. * @deprecated since Symfony 7.4, will be replaced by `__serialize()` in 8.0
  117. */
  118. public function __sleep(): array
  119. {
  120. trigger_deprecation('symfony/http-kernel', '7.4', 'Calling "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this));
  121. return ['data'];
  122. }
  123. /**
  124. * @deprecated since Symfony 7.4, will be replaced by `__unserialize()` in 8.0
  125. */
  126. public function __wakeup(): void
  127. {
  128. trigger_deprecation('symfony/http-kernel', '7.4', 'Calling "%s::__wakeup()" is deprecated, use "__unserialize()" instead.', get_debug_type($this));
  129. }
  130. /**
  131. * @return void
  132. */
  133. public function reset()
  134. {
  135. $this->data = [];
  136. }
  137. }