XML.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <?php
  2. class PHPParser_Unserializer_XML implements PHPParser_Unserializer
  3. {
  4. protected $reader;
  5. public function __construct() {
  6. $this->reader = new XMLReader;
  7. }
  8. public function unserialize($string) {
  9. $this->reader->XML($string);
  10. $this->reader->read();
  11. if ('AST' !== $this->reader->name) {
  12. throw new DomainException('AST root element not found');
  13. }
  14. return $this->read($this->reader->depth);
  15. }
  16. protected function read($depthLimit, $throw = true, &$nodeFound = null) {
  17. $nodeFound = true;
  18. while ($this->reader->read() && $depthLimit < $this->reader->depth) {
  19. if (XMLReader::ELEMENT !== $this->reader->nodeType) {
  20. continue;
  21. }
  22. if ('node' === $this->reader->prefix) {
  23. return $this->readNode();
  24. } elseif ('scalar' === $this->reader->prefix) {
  25. return $this->readScalar();
  26. } elseif ('comment' === $this->reader->name) {
  27. return $this->readComment();
  28. } else {
  29. throw new DomainException(sprintf('Unexpected node of type "%s"', $this->reader->name));
  30. }
  31. }
  32. $nodeFound = false;
  33. if ($throw) {
  34. throw new DomainException('Expected node or scalar');
  35. }
  36. }
  37. protected function readNode()
  38. {
  39. $className = 'PHPParser_Node_' . $this->reader->localName;
  40. // create the node without calling it's constructor
  41. $node = unserialize(
  42. sprintf(
  43. "O:%d:\"%s\":2:{s:11:\"\0*\0subNodes\";a:0:{}s:13:\"\0*\0attributes\";a:0:{}}",
  44. strlen($className), $className
  45. )
  46. );
  47. $depthLimit = $this->reader->depth;
  48. while ($this->reader->read() && $depthLimit < $this->reader->depth) {
  49. if (XMLReader::ELEMENT !== $this->reader->nodeType) {
  50. continue;
  51. }
  52. $type = $this->reader->prefix;
  53. if ('subNode' !== $type && 'attribute' !== $type) {
  54. throw new DomainException(
  55. sprintf('Expected sub node or attribute, got node of type "%s"', $this->reader->name)
  56. );
  57. }
  58. $name = $this->reader->localName;
  59. $value = $this->read($this->reader->depth);
  60. if ('subNode' === $type) {
  61. $node->$name = $value;
  62. } else {
  63. $node->setAttribute($name, $value);
  64. }
  65. }
  66. return $node;
  67. }
  68. protected function readScalar() {
  69. switch ($name = $this->reader->localName) {
  70. case 'array':
  71. $depth = $this->reader->depth;
  72. $array = array();
  73. while (true) {
  74. $node = $this->read($depth, false, $nodeFound);
  75. if (!$nodeFound) {
  76. break;
  77. }
  78. $array[] = $node;
  79. }
  80. return $array;
  81. case 'string':
  82. return $this->reader->readString();
  83. case 'int':
  84. $text = $this->reader->readString();
  85. if (false === $int = filter_var($text, FILTER_VALIDATE_INT)) {
  86. throw new DomainException(sprintf('"%s" is not a valid integer', $text));
  87. }
  88. return $int;
  89. case 'float':
  90. $text = $this->reader->readString();
  91. if (false === $float = filter_var($text, FILTER_VALIDATE_FLOAT)) {
  92. throw new DomainException(sprintf('"%s" is not a valid float', $text));
  93. }
  94. return $float;
  95. case 'true':
  96. case 'false':
  97. case 'null':
  98. if (!$this->reader->isEmptyElement) {
  99. throw new DomainException(sprintf('"%s" scalar must be empty', $name));
  100. }
  101. return constant($name);
  102. default:
  103. throw new DomainException(sprintf('Unknown scalar type "%s"', $name));
  104. }
  105. }
  106. protected function readComment() {
  107. $className = $this->reader->getAttribute('isDocComment') === 'true'
  108. ? 'PHPParser_Comment_Doc'
  109. : 'PHPParser_Comment'
  110. ;
  111. return new $className(
  112. $this->reader->readString(),
  113. $this->reader->getAttribute('line')
  114. );
  115. }
  116. }