Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. NodeTraverser.php

class NodeTraverser

Same name in this branch
  1. 11.1.x vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php \PHPStan\PhpDocParser\Ast\NodeTraverser
  2. 11.1.x vendor/twig/twig/src/NodeTraverser.php \Twig\NodeTraverser

Hierarchy

  • class \PhpParser\NodeTraverser implements \PhpParser\NodeTraverserInterface

Expanded class hierarchy of NodeTraverser

5 files declare their use of NodeTraverser
Calculator.php in vendor/sebastian/complexity/src/Calculator.php
CodeUnitFindingVisitor.php in vendor/phpunit/php-code-coverage/src/StaticAnalysis/CodeUnitFindingVisitor.php
ComplexityCalculatingVisitor.php in vendor/sebastian/complexity/src/Visitor/ComplexityCalculatingVisitor.php
Counter.php in vendor/sebastian/lines-of-code/src/Counter.php
ParsingFileAnalyser.php in vendor/phpunit/php-code-coverage/src/StaticAnalysis/ParsingFileAnalyser.php

File

vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php, line 5

Namespace

PhpParser
View source
class NodeTraverser implements NodeTraverserInterface {
    
    /**
     * @deprecated Use NodeVisitor::DONT_TRAVERSE_CHILDREN instead.
     */
    public const DONT_TRAVERSE_CHILDREN = NodeVisitor::DONT_TRAVERSE_CHILDREN;
    
    /**
     * @deprecated Use NodeVisitor::STOP_TRAVERSAL instead.
     */
    public const STOP_TRAVERSAL = NodeVisitor::STOP_TRAVERSAL;
    
    /**
     * @deprecated Use NodeVisitor::REMOVE_NODE instead.
     */
    public const REMOVE_NODE = NodeVisitor::REMOVE_NODE;
    
    /**
     * @deprecated Use NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN instead.
     */
    public const DONT_TRAVERSE_CURRENT_AND_CHILDREN = NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
    
    /** @var list<NodeVisitor> Visitors */
    protected array $visitors = [];
    
    /** @var bool Whether traversal should be stopped */
    protected bool $stopTraversal;
    
    /**
     * Create a traverser with the given visitors.
     *
     * @param NodeVisitor ...$visitors Node visitors
     */
    public function __construct(NodeVisitor ...$visitors) {
        $this->visitors = $visitors;
    }
    
    /**
     * Adds a visitor.
     *
     * @param NodeVisitor $visitor Visitor to add
     */
    public function addVisitor(NodeVisitor $visitor) : void {
        $this->visitors[] = $visitor;
    }
    
    /**
     * Removes an added visitor.
     */
    public function removeVisitor(NodeVisitor $visitor) : void {
        $index = array_search($visitor, $this->visitors);
        if ($index !== false) {
            array_splice($this->visitors, $index, 1, []);
        }
    }
    
    /**
     * Traverses an array of nodes using the registered visitors.
     *
     * @param Node[] $nodes Array of nodes
     *
     * @return Node[] Traversed array of nodes
     */
    public function traverse(array $nodes) : array {
        $this->stopTraversal = false;
        foreach ($this->visitors as $visitor) {
            if (null !== ($return = $visitor->beforeTraverse($nodes))) {
                $nodes = $return;
            }
        }
        $nodes = $this->traverseArray($nodes);
        for ($i = \count($this->visitors) - 1; $i >= 0; --$i) {
            $visitor = $this->visitors[$i];
            if (null !== ($return = $visitor->afterTraverse($nodes))) {
                $nodes = $return;
            }
        }
        return $nodes;
    }
    
    /**
     * Recursively traverse a node.
     *
     * @param Node $node Node to traverse.
     */
    protected function traverseNode(Node $node) : void {
        foreach ($node->getSubNodeNames() as $name) {
            $subNode = $node->{$name};
            if (\is_array($subNode)) {
                $node->{$name} = $this->traverseArray($subNode);
                if ($this->stopTraversal) {
                    break;
                }
            }
            elseif ($subNode instanceof Node) {
                $traverseChildren = true;
                $visitorIndex = -1;
                foreach ($this->visitors as $visitorIndex => $visitor) {
                    $return = $visitor->enterNode($subNode);
                    if (null !== $return) {
                        if ($return instanceof Node) {
                            $this->ensureReplacementReasonable($subNode, $return);
                            $subNode = $node->{$name} = $return;
                        }
                        elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) {
                            $traverseChildren = false;
                        }
                        elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {
                            $traverseChildren = false;
                            break;
                        }
                        elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
                            $this->stopTraversal = true;
                            break 2;
                        }
                        elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
                            $node->{$name} = null;
                            continue 2;
                        }
                        else {
                            throw new \LogicException('enterNode() returned invalid value of type ' . gettype($return));
                        }
                    }
                }
                if ($traverseChildren) {
                    $this->traverseNode($subNode);
                    if ($this->stopTraversal) {
                        break;
                    }
                }
                for (; $visitorIndex >= 0; --$visitorIndex) {
                    $visitor = $this->visitors[$visitorIndex];
                    $return = $visitor->leaveNode($subNode);
                    if (null !== $return) {
                        if ($return instanceof Node) {
                            $this->ensureReplacementReasonable($subNode, $return);
                            $subNode = $node->{$name} = $return;
                        }
                        elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
                            $this->stopTraversal = true;
                            break 2;
                        }
                        elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
                            $node->{$name} = null;
                            break;
                        }
                        elseif (\is_array($return)) {
                            throw new \LogicException('leaveNode() may only return an array ' . 'if the parent structure is an array');
                        }
                        else {
                            throw new \LogicException('leaveNode() returned invalid value of type ' . gettype($return));
                        }
                    }
                }
            }
        }
    }
    
    /**
     * Recursively traverse array (usually of nodes).
     *
     * @param array $nodes Array to traverse
     *
     * @return array Result of traversal (may be original array or changed one)
     */
    protected function traverseArray(array $nodes) : array {
        $doNodes = [];
        foreach ($nodes as $i => $node) {
            if ($node instanceof Node) {
                $traverseChildren = true;
                $visitorIndex = -1;
                foreach ($this->visitors as $visitorIndex => $visitor) {
                    $return = $visitor->enterNode($node);
                    if (null !== $return) {
                        if ($return instanceof Node) {
                            $this->ensureReplacementReasonable($node, $return);
                            $nodes[$i] = $node = $return;
                        }
                        elseif (\is_array($return)) {
                            $doNodes[] = [
                                $i,
                                $return,
                            ];
                            continue 2;
                        }
                        elseif (NodeVisitor::REMOVE_NODE === $return) {
                            $doNodes[] = [
                                $i,
                                [],
                            ];
                            continue 2;
                        }
                        elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) {
                            $traverseChildren = false;
                        }
                        elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {
                            $traverseChildren = false;
                            break;
                        }
                        elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
                            $this->stopTraversal = true;
                            break 2;
                        }
                        elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
                            throw new \LogicException('REPLACE_WITH_NULL can not be used if the parent structure is an array');
                        }
                        else {
                            throw new \LogicException('enterNode() returned invalid value of type ' . gettype($return));
                        }
                    }
                }
                if ($traverseChildren) {
                    $this->traverseNode($node);
                    if ($this->stopTraversal) {
                        break;
                    }
                }
                for (; $visitorIndex >= 0; --$visitorIndex) {
                    $visitor = $this->visitors[$visitorIndex];
                    $return = $visitor->leaveNode($node);
                    if (null !== $return) {
                        if ($return instanceof Node) {
                            $this->ensureReplacementReasonable($node, $return);
                            $nodes[$i] = $node = $return;
                        }
                        elseif (\is_array($return)) {
                            $doNodes[] = [
                                $i,
                                $return,
                            ];
                            break;
                        }
                        elseif (NodeVisitor::REMOVE_NODE === $return) {
                            $doNodes[] = [
                                $i,
                                [],
                            ];
                            break;
                        }
                        elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
                            $this->stopTraversal = true;
                            break 2;
                        }
                        elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
                            throw new \LogicException('REPLACE_WITH_NULL can not be used if the parent structure is an array');
                        }
                        else {
                            throw new \LogicException('leaveNode() returned invalid value of type ' . gettype($return));
                        }
                    }
                }
            }
            elseif (\is_array($node)) {
                throw new \LogicException('Invalid node structure: Contains nested arrays');
            }
        }
        if (!empty($doNodes)) {
            while (list($i, $replace) = array_pop($doNodes)) {
                array_splice($nodes, $i, 1, $replace);
            }
        }
        return $nodes;
    }
    private function ensureReplacementReasonable(Node $old, Node $new) : void {
        if ($old instanceof Node\Stmt && $new instanceof Node\Expr) {
            throw new \LogicException("Trying to replace statement ({$old->getType()}) " . "with expression ({$new->getType()}). Are you missing a " . "Stmt_Expression wrapper?");
        }
        if ($old instanceof Node\Expr && $new instanceof Node\Stmt) {
            throw new \LogicException("Trying to replace expression ({$old->getType()}) " . "with statement ({$new->getType()})");
        }
    }

}

Members

Title Sort descending Deprecated Modifiers Object type Summary Overriden Title
NodeTraverser::$stopTraversal protected property @var bool Whether traversal should be stopped
NodeTraverser::$visitors protected property @var list&lt;NodeVisitor&gt; Visitors
NodeTraverser::addVisitor public function Adds a visitor. Overrides NodeTraverserInterface::addVisitor
NodeTraverser::DONT_TRAVERSE_CHILDREN Deprecated public constant
NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN Deprecated public constant
NodeTraverser::ensureReplacementReasonable private function
NodeTraverser::removeVisitor public function Removes an added visitor. Overrides NodeTraverserInterface::removeVisitor
NodeTraverser::REMOVE_NODE Deprecated public constant
NodeTraverser::STOP_TRAVERSAL Deprecated public constant
NodeTraverser::traverse public function Traverses an array of nodes using the registered visitors. Overrides NodeTraverserInterface::traverse
NodeTraverser::traverseArray protected function Recursively traverse array (usually of nodes).
NodeTraverser::traverseNode protected function Recursively traverse a node.
NodeTraverser::__construct public function Create a traverser with the given visitors.

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal