1<?php declare(strict_types=1); 2 3namespace PhpParser; 4 5use PhpParser\NodeVisitor\FindingVisitor; 6use PhpParser\NodeVisitor\FirstFindingVisitor; 7 8class NodeFinder { 9 /** 10 * Find all nodes satisfying a filter callback. 11 * 12 * @param Node|Node[] $nodes Single node or array of nodes to search in 13 * @param callable $filter Filter callback: function(Node $node) : bool 14 * 15 * @return Node[] Found nodes satisfying the filter callback 16 */ 17 public function find($nodes, callable $filter): array { 18 if ($nodes === []) { 19 return []; 20 } 21 22 if (!is_array($nodes)) { 23 $nodes = [$nodes]; 24 } 25 26 $visitor = new FindingVisitor($filter); 27 28 $traverser = new NodeTraverser($visitor); 29 $traverser->traverse($nodes); 30 31 return $visitor->getFoundNodes(); 32 } 33 34 /** 35 * Find all nodes that are instances of a certain class. 36 37 * @template TNode as Node 38 * 39 * @param Node|Node[] $nodes Single node or array of nodes to search in 40 * @param class-string<TNode> $class Class name 41 * 42 * @return TNode[] Found nodes (all instances of $class) 43 */ 44 public function findInstanceOf($nodes, string $class): array { 45 return $this->find($nodes, function ($node) use ($class) { 46 return $node instanceof $class; 47 }); 48 } 49 50 /** 51 * Find first node satisfying a filter callback. 52 * 53 * @param Node|Node[] $nodes Single node or array of nodes to search in 54 * @param callable $filter Filter callback: function(Node $node) : bool 55 * 56 * @return null|Node Found node (or null if none found) 57 */ 58 public function findFirst($nodes, callable $filter): ?Node { 59 if ($nodes === []) { 60 return null; 61 } 62 63 if (!is_array($nodes)) { 64 $nodes = [$nodes]; 65 } 66 67 $visitor = new FirstFindingVisitor($filter); 68 69 $traverser = new NodeTraverser($visitor); 70 $traverser->traverse($nodes); 71 72 return $visitor->getFoundNode(); 73 } 74 75 /** 76 * Find first node that is an instance of a certain class. 77 * 78 * @template TNode as Node 79 * 80 * @param Node|Node[] $nodes Single node or array of nodes to search in 81 * @param class-string<TNode> $class Class name 82 * 83 * @return null|TNode Found node, which is an instance of $class (or null if none found) 84 */ 85 public function findFirstInstanceOf($nodes, string $class): ?Node { 86 return $this->findFirst($nodes, function ($node) use ($class) { 87 return $node instanceof $class; 88 }); 89 } 90} 91