mirror of
https://github.com/phabelio/PHP-Parser.git
synced 2025-01-21 21:01:15 +01:00
Stop using ArrayObject for nodes
Instead manually implement IteratorAggregate and define the required magic methods. The reasoning behind this is: a) Extending ArrayObject is always risky, because a lot of magic which is known to be buggy is involved b) This allows to lateron change the implementation for the nodes altogether, for example it could be changed to using real public fields instead of a $subNodes array.
This commit is contained in:
parent
126efbc056
commit
c7c94f38f1
@ -1,7 +1,8 @@
|
||||
<?php
|
||||
|
||||
abstract class PHPParser_NodeAbstract extends ArrayObject implements PHPParser_Node
|
||||
abstract class PHPParser_NodeAbstract implements PHPParser_Node, IteratorAggregate
|
||||
{
|
||||
protected $subNodes;
|
||||
protected $line;
|
||||
protected $docComment;
|
||||
|
||||
@ -13,8 +14,7 @@ abstract class PHPParser_NodeAbstract extends ArrayObject implements PHPParser_N
|
||||
* @param null|string $docComment Nearest doc comment
|
||||
*/
|
||||
public function __construct(array $subNodes, $line = -1, $docComment = null) {
|
||||
parent::__construct($subNodes, ArrayObject::ARRAY_AS_PROPS);
|
||||
|
||||
$this->subNodes = $subNodes;
|
||||
$this->line = $line;
|
||||
$this->docComment = $docComment;
|
||||
}
|
||||
@ -45,4 +45,22 @@ abstract class PHPParser_NodeAbstract extends ArrayObject implements PHPParser_N
|
||||
public function getDocComment() {
|
||||
return $this->docComment;
|
||||
}
|
||||
|
||||
/* Magic interfaces */
|
||||
|
||||
public function &__get($name) {
|
||||
return $this->subNodes[$name];
|
||||
}
|
||||
public function __set($name, $value) {
|
||||
$this->subNodes[$name] = $value;
|
||||
}
|
||||
public function __isset($name) {
|
||||
return isset($this->subNodes[$name]);
|
||||
}
|
||||
public function __unset($name) {
|
||||
unset($this->subNodes[$name]);
|
||||
}
|
||||
public function getIterator() {
|
||||
return new ArrayIterator($this->subNodes);
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ class PHPParser_NodeTraverser
|
||||
}
|
||||
}
|
||||
|
||||
$nodes = $this->_traverse($nodes);
|
||||
$nodes = $this->traverseArray($nodes);
|
||||
|
||||
foreach ($this->visitors as $visitor) {
|
||||
if (null !== $return = $visitor->afterTraverse($nodes)) {
|
||||
@ -48,53 +48,73 @@ class PHPParser_NodeTraverser
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
protected function _traverse($node) {
|
||||
$doNodes = array();
|
||||
|
||||
protected function traverseNode(PHPParser_Node $node) {
|
||||
foreach ($node as $name => $subNode) {
|
||||
if (is_array($subNode)) {
|
||||
$node[$name] = $this->_traverse($subNode, $this->visitors);
|
||||
$node->$name = $this->traverseArray($subNode);
|
||||
} elseif ($subNode instanceof PHPParser_Node) {
|
||||
foreach ($this->visitors as $visitor) {
|
||||
if (null !== $return = $visitor->enterNode($subNode)) {
|
||||
$node[$name] = $return;
|
||||
$node->$name = $return;
|
||||
}
|
||||
}
|
||||
|
||||
$node[$name] = $this->_traverse($subNode, $this->visitors);
|
||||
$node->$name = $this->traverseNode($subNode);
|
||||
|
||||
foreach ($this->visitors as $i => $visitor) {
|
||||
$return = $visitor->leaveNode($subNode);
|
||||
foreach ($this->visitors as $visitor) {
|
||||
if (null !== $return = $visitor->leaveNode($subNode)) {
|
||||
$node->$name = $return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
protected function traverseArray(array $nodes) {
|
||||
$doNodes = array();
|
||||
|
||||
foreach ($nodes as $i => $node) {
|
||||
if (is_array($node)) {
|
||||
$nodes[$i] = $this->traverseArray($node);
|
||||
} elseif ($node instanceof PHPParser_Node) {
|
||||
foreach ($this->visitors as $visitor) {
|
||||
if (null !== $return = $visitor->enterNode($node)) {
|
||||
$nodes[$i] = $return;
|
||||
}
|
||||
}
|
||||
|
||||
$nodes[$i] = $this->traverseNode($node);
|
||||
|
||||
foreach ($this->visitors as $j => $visitor) {
|
||||
$return = $visitor->leaveNode($node);
|
||||
|
||||
if (false === $return) {
|
||||
$doNodes[] = array($name, array());
|
||||
$doNodes[] = array($i, array());
|
||||
break;
|
||||
} elseif (is_array($return)) {
|
||||
// traverse replacement nodes using all visitors apart from the one that
|
||||
// did the change
|
||||
unset($this->visitors[$i]);
|
||||
$return = $this->_traverse($return);
|
||||
$this->visitors[$i] = $visitor;
|
||||
unset($this->visitors[$j]);
|
||||
$return = $this->traverseArray($return);
|
||||
$this->visitors[$j] = $visitor;
|
||||
|
||||
$doNodes[] = array($name, $return);
|
||||
$doNodes[] = array($i, $return);
|
||||
break;
|
||||
} elseif (null !== $return) {
|
||||
$node[$name] = $return;
|
||||
$nodes[$i] = $return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($doNodes)) {
|
||||
if (!is_array($node)) {
|
||||
throw new Exception('Nodes can only be merged if the parent is an array');
|
||||
}
|
||||
|
||||
while (list($key, $replace) = array_pop($doNodes)) {
|
||||
array_splice($node, $key, 1, $replace);
|
||||
while (list($i, $replace) = array_pop($doNodes)) {
|
||||
array_splice($nodes, $i, 1, $replace);
|
||||
}
|
||||
}
|
||||
|
||||
return $node;
|
||||
return $nodes;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user