Chris@13: Name resolution Chris@13: =============== Chris@13: Chris@13: Since the introduction of namespaces in PHP 5.3, literal names in PHP code are subject to a Chris@13: relatively complex name resolution process, which is based on the current namespace, the current Chris@13: import table state, as well the type of the referenced symbol. PHP-Parser implements name Chris@13: resolution and related functionality, both as reusable logic (NameContext), as well as a node Chris@13: visitor (NameResolver) based on it. Chris@13: Chris@13: The NameResolver visitor Chris@13: ------------------------ Chris@13: Chris@13: The `NameResolver` visitor can (and for nearly all uses of the AST, is) be applied to resolve names Chris@13: to their fully-qualified form, to the degree that this is possible. Chris@13: Chris@13: ```php Chris@13: $nameResolver = new PhpParser\NodeVisitor\NameResolver; Chris@13: $nodeTraverser = new PhpParser\NodeTraverser; Chris@13: $nodeTraverser->addVisitor($nameResolver); Chris@13: Chris@13: // Resolve names Chris@13: $stmts = $nodeTraverser->traverse($stmts); Chris@13: ``` Chris@13: Chris@13: In the default configuration, the name resolver will perform three actions: Chris@13: Chris@13: * Declarations of functions, classes, interfaces, traits and global constants will have a Chris@13: `namespacedName` property added, which contains the function/class/etc name including the Chris@13: namespace prefix. For historic reasons this is a **property** rather than an attribute. Chris@13: * Names will be replaced by fully qualified resolved names, which are instances of Chris@13: `Node\Name\FullyQualified`. Chris@13: * Unqualified function and constant names inside a namespace cannot be statically resolved. Inside Chris@13: a namespace `Foo`, a call to `strlen()` may either refer to the namespaced `\Foo\strlen()`, or Chris@13: the global `\strlen()`. Because PHP-Parser does not have the necessary context to decide this, Chris@13: such names are left unresolved. Additionally a `namespacedName` **attribute** is added to the Chris@13: name node. Chris@13: Chris@13: The name resolver accepts an option array as the second argument, with the following default values: Chris@13: Chris@13: ```php Chris@13: $nameResolver = new PhpParser\NodeVisitor\NameResolver(null, [ Chris@13: 'preserveOriginalNames' => false, Chris@13: 'replaceNodes' => true, Chris@13: ]); Chris@13: ``` Chris@13: Chris@13: If the `preserveOriginalNames` option is enabled, then the resolved (fully qualified) name will have Chris@13: an `originalName` attribute, which contains the unresolved name. Chris@13: Chris@13: If the `replaceNodes` option is disabled, then names will no longer be resolved in-place. Instead a Chris@13: `resolvedName` attribute will be added to each name, which contains the resolved (fully qualified) Chris@13: name. Once again, if an unqualified function or constant name cannot be resolved, then the Chris@13: `resolvedName` attribute will not be present, and instead a `namespacedName` attribute is added. Chris@13: Chris@13: The `replaceNodes` attribute is useful if you wish to perform modifications on the AST, as you Chris@13: probably do not wish the resoluting code to have fully resolved names as a side-effect. Chris@13: Chris@13: The NameContext Chris@13: --------------- Chris@13: Chris@13: The actual name resolution logic is implemented in the `NameContext` class, which has the following Chris@13: public API: Chris@13: Chris@13: ```php Chris@13: class NameContext { Chris@13: public function __construct(ErrorHandler $errorHandler); Chris@13: public function startNamespace(Name $namespace = null); Chris@13: public function addAlias(Name $name, string $aliasName, int $type, array $errorAttrs = []); Chris@13: Chris@13: public function getNamespace(); Chris@13: public function getResolvedName(Name $name, int $type); Chris@13: public function getResolvedClassName(Name $name) : Name; Chris@13: public function getPossibleNames(string $name, int $type) : array; Chris@13: public function getShortName(string $name, int $type) : Name; Chris@13: } Chris@13: ``` Chris@13: Chris@13: The `$type` parameters accept on of the `Stmt\Use_::TYPE_*` constants, which represent the three Chris@13: basic symbol types in PHP (functions, constants and everything else). Chris@13: Chris@13: Next to name resolution, the `NameContext` also supports the reverse operation of finding a short Chris@13: representation of a name given the current name resolution environment. Chris@13: Chris@13: The name context is intended to be used for name resolution operations outside the AST itself, such Chris@13: as class names inside doc comments. A visitor running in parallel with the name resolver can access Chris@13: the name context using `$nameResolver->getNameContext()`. Alternatively a visitor can use an Chris@13: independent context and explicitly feed `Namespace` and `Use` nodes to it.