VarExporter.php 3.6 KB

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