VarExporter.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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;
  11. use Symfony\Component\VarExporter\Exception\ExceptionInterface;
  12. use Symfony\Component\VarExporter\Internal\Exporter;
  13. use Symfony\Component\VarExporter\Internal\Hydrator;
  14. use Symfony\Component\VarExporter\Internal\Registry;
  15. use Symfony\Component\VarExporter\Internal\Values;
  16. /**
  17. * Exports serializable PHP values to PHP code.
  18. *
  19. * VarExporter allows serializing PHP data structures to plain PHP code (like var_export())
  20. * while preserving all the semantics associated with serialize() (unlike var_export()).
  21. *
  22. * By leveraging OPcache, the generated PHP code is faster than doing the same with unserialize().
  23. *
  24. * @author Nicolas Grekas <p@tchwork.com>
  25. */
  26. final class VarExporter
  27. {
  28. /**
  29. * Exports a serializable PHP value to PHP code.
  30. *
  31. * @param bool &$isStaticValue Set to true after execution if the provided value is static, false otherwise
  32. * @param bool &$classes Classes found in the value are added to this list as both keys and values
  33. *
  34. * @throws ExceptionInterface When the provided value cannot be serialized
  35. */
  36. public static function export(mixed $value, bool &$isStaticValue = null, array &$foundClasses = []): string
  37. {
  38. $isStaticValue = true;
  39. if (!\is_object($value) && !(\is_array($value) && $value) && !\is_resource($value) || $value instanceof \UnitEnum) {
  40. return Exporter::export($value);
  41. }
  42. $objectsPool = new \SplObjectStorage();
  43. $refsPool = [];
  44. $objectsCount = 0;
  45. try {
  46. $value = Exporter::prepare([$value], $objectsPool, $refsPool, $objectsCount, $isStaticValue)[0];
  47. } finally {
  48. $references = [];
  49. foreach ($refsPool as $i => $v) {
  50. if ($v[0]->count) {
  51. $references[1 + $i] = $v[2];
  52. }
  53. $v[0] = $v[1];
  54. }
  55. }
  56. if ($isStaticValue) {
  57. return Exporter::export($value);
  58. }
  59. $classes = [];
  60. $values = [];
  61. $states = [];
  62. foreach ($objectsPool as $i => $v) {
  63. [, $class, $values[], $wakeup] = $objectsPool[$v];
  64. $foundClasses[$class] = $classes[] = $class;
  65. if (0 < $wakeup) {
  66. $states[$wakeup] = $i;
  67. } elseif (0 > $wakeup) {
  68. $states[-$wakeup] = [$i, array_pop($values)];
  69. $values[] = [];
  70. }
  71. }
  72. ksort($states);
  73. $wakeups = [null];
  74. foreach ($states as $k => $v) {
  75. if (\is_array($v)) {
  76. $wakeups[-$v[0]] = $v[1];
  77. } else {
  78. $wakeups[] = $v;
  79. }
  80. }
  81. if (null === $wakeups[0]) {
  82. unset($wakeups[0]);
  83. }
  84. $properties = [];
  85. foreach ($values as $i => $vars) {
  86. foreach ($vars as $class => $values) {
  87. foreach ($values as $name => $v) {
  88. $properties[$class][$name][$i] = $v;
  89. }
  90. }
  91. }
  92. if ($classes || $references) {
  93. $value = new Hydrator(new Registry($classes), $references ? new Values($references) : null, $properties, $value, $wakeups);
  94. } else {
  95. $isStaticValue = true;
  96. }
  97. return Exporter::export($value);
  98. }
  99. }