VarExporter.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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 mixed $value The value to export
  32. * @param bool &$isStaticValue Set to true after execution if the provided value is static, false otherwise
  33. * @param array &$foundClasses Classes found in the value are added to this list as both keys and values
  34. *
  35. * @throws ExceptionInterface When the provided value cannot be serialized
  36. */
  37. public static function export($value, ?bool &$isStaticValue = null, array &$foundClasses = []): string
  38. {
  39. $isStaticValue = true;
  40. if (!\is_object($value) && !(\is_array($value) && $value) && !\is_resource($value) || $value instanceof \UnitEnum) {
  41. return Exporter::export($value);
  42. }
  43. $objectsPool = new \SplObjectStorage();
  44. $refsPool = [];
  45. $objectsCount = 0;
  46. try {
  47. $value = Exporter::prepare([$value], $objectsPool, $refsPool, $objectsCount, $isStaticValue)[0];
  48. } finally {
  49. $references = [];
  50. foreach ($refsPool as $i => $v) {
  51. if ($v[0]->count) {
  52. $references[1 + $i] = $v[2];
  53. }
  54. $v[0] = $v[1];
  55. }
  56. }
  57. if ($isStaticValue) {
  58. return Exporter::export($value);
  59. }
  60. $classes = [];
  61. $values = [];
  62. $states = [];
  63. foreach ($objectsPool as $i => $v) {
  64. [, $class, $values[], $wakeup] = $objectsPool[$v];
  65. $foundClasses[$class] = $classes[] = $class;
  66. if (0 < $wakeup) {
  67. $states[$wakeup] = $i;
  68. } elseif (0 > $wakeup) {
  69. $states[-$wakeup] = [$i, array_pop($values)];
  70. $values[] = [];
  71. }
  72. }
  73. ksort($states);
  74. $wakeups = [null];
  75. foreach ($states as $v) {
  76. if (\is_array($v)) {
  77. $wakeups[-$v[0]] = $v[1];
  78. } else {
  79. $wakeups[] = $v;
  80. }
  81. }
  82. if (null === $wakeups[0]) {
  83. unset($wakeups[0]);
  84. }
  85. $properties = [];
  86. foreach ($values as $i => $vars) {
  87. foreach ($vars as $class => $values) {
  88. foreach ($values as $name => $v) {
  89. $properties[$class][$name][$i] = $v;
  90. }
  91. }
  92. }
  93. if ($classes || $references) {
  94. $value = new Hydrator(new Registry($classes), $references ? new Values($references) : null, $properties, $value, $wakeups);
  95. } else {
  96. $isStaticValue = true;
  97. }
  98. return Exporter::export($value);
  99. }
  100. }