xref: /PHP-Parser/lib/PhpParser/NodeFinder.php (revision 481fec47)
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