php-parser/lib/PhpParser/NameContext.php

168 lines
5.5 KiB
PHP
Raw Normal View History

<?php
namespace PhpParser;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt;
class NameContext {
/** @var null|Name Current namespace */
protected $namespace;
/** @var array Map of format [aliasType => [aliasName => originalName]] */
protected $aliases = [];
/** @var ErrorHandler Error handler */
protected $errorHandler;
/**
* Create a name context.
*
* @param ErrorHandler $errorHandler Error handling used to report errors
*/
public function __construct(ErrorHandler $errorHandler) {
$this->errorHandler = $errorHandler;
}
/**
* Start a new namespace.
*
* This also resets the alias table.
*
* @param Name|null $namespace Null is the global namespace
*/
public function startNamespace(Name $namespace = null) {
$this->namespace = $namespace;
$this->aliases = [
Stmt\Use_::TYPE_NORMAL => [],
Stmt\Use_::TYPE_FUNCTION => [],
Stmt\Use_::TYPE_CONSTANT => [],
];
}
/**
* Add an alias / import.
*
* @param Name $name Original name
* @param string $aliasName Aliased name
* @param int $type One of Stmt\Use_::TYPE_*
* @param array $errorAttrs Attributes to use to report an error
*/
public function addAlias(Name $name, $aliasName, $type, array $errorAttrs = []) {
// Constant names are case sensitive, everything else case insensitive
if ($type === Stmt\Use_::TYPE_CONSTANT) {
$aliasLookupName = $aliasName;
} else {
$aliasLookupName = strtolower($aliasName);
}
if (isset($this->aliases[$type][$aliasLookupName])) {
$typeStringMap = array(
Stmt\Use_::TYPE_NORMAL => '',
Stmt\Use_::TYPE_FUNCTION => 'function ',
Stmt\Use_::TYPE_CONSTANT => 'const ',
);
$this->errorHandler->handleError(new Error(
sprintf(
'Cannot use %s%s as %s because the name is already in use',
$typeStringMap[$type], $name, $aliasName
),
$errorAttrs
));
return;
}
$this->aliases[$type][$aliasLookupName] = $name;
}
/**
* Get current namespace.
*
* @return null|Name Namespace (or null if global namespace)
*/
public function getNamespace() {
return $this->namespace;
}
/**
* Get resolved class name.
*
* @param Name $name Class ame to resolve
*
* @return Name Resolved name
*/
public function getResolvedClassName(Name $name) {
// don't resolve special class names
if (in_array(strtolower($name->toString()), array('self', 'parent', 'static'))) {
if (!$name->isUnqualified()) {
$this->errorHandler->handleError(new Error(
sprintf("'\\%s' is an invalid class name", $name->toString()),
$name->getAttributes()
));
}
return $name;
}
// fully qualified names are already resolved
if ($name->isFullyQualified()) {
return $name;
}
$aliasName = strtolower($name->getFirst());
if (!$name->isRelative() && isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName])) {
// resolve aliases (for non-relative names)
$alias = $this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName];
return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
}
// if no alias exists prepend current namespace
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
}
/**
* Get resolved function or constant name.
*
* @param Name $name Function or constant name to resolve
* @param int $type One of Stmt\Use_::TYPE_{FUNCTION|CONSTANT}
*
* @return null|Name Resolved name, or null if static resolution is not possible
*/
public function getResolvedOtherName(Name $name, $type) {
// fully qualified names are already resolved
if ($name->isFullyQualified()) {
return $name;
}
// resolve aliases for qualified names
$aliasName = strtolower($name->getFirst());
if ($name->isQualified() && isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName])) {
$alias = $this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName];
return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
}
if ($name->isUnqualified()) {
if ($type === Stmt\Use_::TYPE_CONSTANT) {
// constant aliases are case-sensitive, function aliases case-insensitive
$aliasName = $name->getFirst();
}
if (isset($this->aliases[$type][$aliasName])) {
// resolve unqualified aliases
return new FullyQualified($this->aliases[$type][$aliasName], $name->getAttributes());
}
if (null === $this->namespace) {
// outside of a namespace unaliased unqualified is same as fully qualified
return new FullyQualified($name, $name->getAttributes());
}
// Cannot resolve statically
return null;
}
// if no alias exists prepend current namespace
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
}
}