Chris@13
|
1 Name resolution
|
Chris@13
|
2 ===============
|
Chris@13
|
3
|
Chris@13
|
4 Since the introduction of namespaces in PHP 5.3, literal names in PHP code are subject to a
|
Chris@13
|
5 relatively complex name resolution process, which is based on the current namespace, the current
|
Chris@13
|
6 import table state, as well the type of the referenced symbol. PHP-Parser implements name
|
Chris@13
|
7 resolution and related functionality, both as reusable logic (NameContext), as well as a node
|
Chris@13
|
8 visitor (NameResolver) based on it.
|
Chris@13
|
9
|
Chris@13
|
10 The NameResolver visitor
|
Chris@13
|
11 ------------------------
|
Chris@13
|
12
|
Chris@13
|
13 The `NameResolver` visitor can (and for nearly all uses of the AST, is) be applied to resolve names
|
Chris@13
|
14 to their fully-qualified form, to the degree that this is possible.
|
Chris@13
|
15
|
Chris@13
|
16 ```php
|
Chris@13
|
17 $nameResolver = new PhpParser\NodeVisitor\NameResolver;
|
Chris@13
|
18 $nodeTraverser = new PhpParser\NodeTraverser;
|
Chris@13
|
19 $nodeTraverser->addVisitor($nameResolver);
|
Chris@13
|
20
|
Chris@13
|
21 // Resolve names
|
Chris@13
|
22 $stmts = $nodeTraverser->traverse($stmts);
|
Chris@13
|
23 ```
|
Chris@13
|
24
|
Chris@13
|
25 In the default configuration, the name resolver will perform three actions:
|
Chris@13
|
26
|
Chris@13
|
27 * Declarations of functions, classes, interfaces, traits and global constants will have a
|
Chris@13
|
28 `namespacedName` property added, which contains the function/class/etc name including the
|
Chris@13
|
29 namespace prefix. For historic reasons this is a **property** rather than an attribute.
|
Chris@13
|
30 * Names will be replaced by fully qualified resolved names, which are instances of
|
Chris@13
|
31 `Node\Name\FullyQualified`.
|
Chris@13
|
32 * Unqualified function and constant names inside a namespace cannot be statically resolved. Inside
|
Chris@13
|
33 a namespace `Foo`, a call to `strlen()` may either refer to the namespaced `\Foo\strlen()`, or
|
Chris@13
|
34 the global `\strlen()`. Because PHP-Parser does not have the necessary context to decide this,
|
Chris@13
|
35 such names are left unresolved. Additionally a `namespacedName` **attribute** is added to the
|
Chris@13
|
36 name node.
|
Chris@13
|
37
|
Chris@13
|
38 The name resolver accepts an option array as the second argument, with the following default values:
|
Chris@13
|
39
|
Chris@13
|
40 ```php
|
Chris@13
|
41 $nameResolver = new PhpParser\NodeVisitor\NameResolver(null, [
|
Chris@13
|
42 'preserveOriginalNames' => false,
|
Chris@13
|
43 'replaceNodes' => true,
|
Chris@13
|
44 ]);
|
Chris@13
|
45 ```
|
Chris@13
|
46
|
Chris@13
|
47 If the `preserveOriginalNames` option is enabled, then the resolved (fully qualified) name will have
|
Chris@13
|
48 an `originalName` attribute, which contains the unresolved name.
|
Chris@13
|
49
|
Chris@13
|
50 If the `replaceNodes` option is disabled, then names will no longer be resolved in-place. Instead a
|
Chris@13
|
51 `resolvedName` attribute will be added to each name, which contains the resolved (fully qualified)
|
Chris@13
|
52 name. Once again, if an unqualified function or constant name cannot be resolved, then the
|
Chris@13
|
53 `resolvedName` attribute will not be present, and instead a `namespacedName` attribute is added.
|
Chris@13
|
54
|
Chris@13
|
55 The `replaceNodes` attribute is useful if you wish to perform modifications on the AST, as you
|
Chris@13
|
56 probably do not wish the resoluting code to have fully resolved names as a side-effect.
|
Chris@13
|
57
|
Chris@13
|
58 The NameContext
|
Chris@13
|
59 ---------------
|
Chris@13
|
60
|
Chris@13
|
61 The actual name resolution logic is implemented in the `NameContext` class, which has the following
|
Chris@13
|
62 public API:
|
Chris@13
|
63
|
Chris@13
|
64 ```php
|
Chris@13
|
65 class NameContext {
|
Chris@13
|
66 public function __construct(ErrorHandler $errorHandler);
|
Chris@13
|
67 public function startNamespace(Name $namespace = null);
|
Chris@13
|
68 public function addAlias(Name $name, string $aliasName, int $type, array $errorAttrs = []);
|
Chris@13
|
69
|
Chris@13
|
70 public function getNamespace();
|
Chris@13
|
71 public function getResolvedName(Name $name, int $type);
|
Chris@13
|
72 public function getResolvedClassName(Name $name) : Name;
|
Chris@13
|
73 public function getPossibleNames(string $name, int $type) : array;
|
Chris@13
|
74 public function getShortName(string $name, int $type) : Name;
|
Chris@13
|
75 }
|
Chris@13
|
76 ```
|
Chris@13
|
77
|
Chris@13
|
78 The `$type` parameters accept on of the `Stmt\Use_::TYPE_*` constants, which represent the three
|
Chris@13
|
79 basic symbol types in PHP (functions, constants and everything else).
|
Chris@13
|
80
|
Chris@13
|
81 Next to name resolution, the `NameContext` also supports the reverse operation of finding a short
|
Chris@13
|
82 representation of a name given the current name resolution environment.
|
Chris@13
|
83
|
Chris@13
|
84 The name context is intended to be used for name resolution operations outside the AST itself, such
|
Chris@13
|
85 as class names inside doc comments. A visitor running in parallel with the name resolver can access
|
Chris@13
|
86 the name context using `$nameResolver->getNameContext()`. Alternatively a visitor can use an
|
Chris@13
|
87 independent context and explicitly feed `Namespace` and `Use` nodes to it. |