Chris@0: reader = new XMLReader; Chris@0: } Chris@0: Chris@0: public function unserialize($string) { Chris@0: $this->reader->XML($string); Chris@0: Chris@0: $this->reader->read(); Chris@0: if ('AST' !== $this->reader->name) { Chris@0: throw new DomainException('AST root element not found'); Chris@0: } Chris@0: Chris@0: return $this->read($this->reader->depth); Chris@0: } Chris@0: Chris@0: protected function read($depthLimit, $throw = true, &$nodeFound = null) { Chris@0: $nodeFound = true; Chris@0: while ($this->reader->read() && $depthLimit < $this->reader->depth) { Chris@0: if (XMLReader::ELEMENT !== $this->reader->nodeType) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: if ('node' === $this->reader->prefix) { Chris@0: return $this->readNode(); Chris@0: } elseif ('scalar' === $this->reader->prefix) { Chris@0: return $this->readScalar(); Chris@0: } elseif ('comment' === $this->reader->name) { Chris@0: return $this->readComment(); Chris@0: } else { Chris@0: throw new DomainException(sprintf('Unexpected node of type "%s"', $this->reader->name)); Chris@0: } Chris@0: } Chris@0: Chris@0: $nodeFound = false; Chris@0: if ($throw) { Chris@0: throw new DomainException('Expected node or scalar'); Chris@0: } Chris@0: } Chris@0: Chris@0: protected function readNode() { Chris@0: $className = $this->getClassNameFromType($this->reader->localName); Chris@0: Chris@0: // create the node without calling it's constructor Chris@0: $node = unserialize( Chris@0: sprintf( Chris@0: "O:%d:\"%s\":1:{s:13:\"\0*\0attributes\";a:0:{}}", Chris@0: strlen($className), $className Chris@0: ) Chris@0: ); Chris@0: Chris@0: $depthLimit = $this->reader->depth; Chris@0: while ($this->reader->read() && $depthLimit < $this->reader->depth) { Chris@0: if (XMLReader::ELEMENT !== $this->reader->nodeType) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $type = $this->reader->prefix; Chris@0: if ('subNode' !== $type && 'attribute' !== $type) { Chris@0: throw new DomainException( Chris@0: sprintf('Expected sub node or attribute, got node of type "%s"', $this->reader->name) Chris@0: ); Chris@0: } Chris@0: Chris@0: $name = $this->reader->localName; Chris@0: $value = $this->read($this->reader->depth); Chris@0: Chris@0: if ('subNode' === $type) { Chris@0: $node->$name = $value; Chris@0: } else { Chris@0: $node->setAttribute($name, $value); Chris@0: } Chris@0: } Chris@0: Chris@0: return $node; Chris@0: } Chris@0: Chris@0: protected function readScalar() { Chris@0: switch ($name = $this->reader->localName) { Chris@0: case 'array': Chris@0: $depth = $this->reader->depth; Chris@0: $array = array(); Chris@0: while (true) { Chris@0: $node = $this->read($depth, false, $nodeFound); Chris@0: if (!$nodeFound) { Chris@0: break; Chris@0: } Chris@0: $array[] = $node; Chris@0: } Chris@0: return $array; Chris@0: case 'string': Chris@0: return $this->reader->readString(); Chris@0: case 'int': Chris@0: return $this->parseInt($this->reader->readString()); Chris@0: case 'float': Chris@0: $text = $this->reader->readString(); Chris@0: if (false === $float = filter_var($text, FILTER_VALIDATE_FLOAT)) { Chris@0: throw new DomainException(sprintf('"%s" is not a valid float', $text)); Chris@0: } Chris@0: return $float; Chris@0: case 'true': Chris@0: case 'false': Chris@0: case 'null': Chris@0: if (!$this->reader->isEmptyElement) { Chris@0: throw new DomainException(sprintf('"%s" scalar must be empty', $name)); Chris@0: } Chris@0: return constant($name); Chris@0: default: Chris@0: throw new DomainException(sprintf('Unknown scalar type "%s"', $name)); Chris@0: } Chris@0: } Chris@0: Chris@0: private function parseInt($text) { Chris@0: if (false === $int = filter_var($text, FILTER_VALIDATE_INT)) { Chris@0: throw new DomainException(sprintf('"%s" is not a valid integer', $text)); Chris@0: } Chris@0: return $int; Chris@0: } Chris@0: Chris@0: protected function readComment() { Chris@0: $className = $this->reader->getAttribute('isDocComment') === 'true' Chris@0: ? 'PhpParser\Comment\Doc' Chris@0: : 'PhpParser\Comment' Chris@0: ; Chris@0: return new $className( Chris@0: $this->reader->readString(), Chris@0: $this->parseInt($this->reader->getAttribute('line')) Chris@0: ); Chris@0: } Chris@0: Chris@0: protected function getClassNameFromType($type) { Chris@0: $className = 'PhpParser\\Node\\' . strtr($type, '_', '\\'); Chris@0: if (!class_exists($className)) { Chris@0: $className .= '_'; Chris@0: } Chris@0: if (!class_exists($className)) { Chris@0: throw new DomainException(sprintf('Unknown node type "%s"', $type)); Chris@0: } Chris@0: return $className; Chris@0: } Chris@0: }