NameResolver.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <?php
  2. class PHPParser_NodeVisitor_NameResolver extends PHPParser_NodeVisitorAbstract
  3. {
  4. /**
  5. * @var null|PHPParser_Node_Name Current namespace
  6. */
  7. protected $namespace;
  8. /**
  9. * @var array Currently defined namespace and class aliases
  10. */
  11. protected $aliases;
  12. public function beforeTraverse(array $nodes) {
  13. $this->namespace = null;
  14. $this->aliases = array();
  15. }
  16. public function enterNode(PHPParser_Node $node) {
  17. if ($node instanceof PHPParser_Node_Stmt_Namespace) {
  18. $this->namespace = $node->name;
  19. $this->aliases = array();
  20. } elseif ($node instanceof PHPParser_Node_Stmt_UseUse) {
  21. if (isset($this->aliases[$node->alias])) {
  22. throw new PHPParser_Error(
  23. sprintf(
  24. 'Cannot use "%s" as "%s" because the name is already in use',
  25. $node->name, $node->alias
  26. ),
  27. $node->getLine()
  28. );
  29. }
  30. $this->aliases[$node->alias] = $node->name;
  31. } elseif ($node instanceof PHPParser_Node_Stmt_Class) {
  32. if (null !== $node->extends) {
  33. $node->extends = $this->resolveClassName($node->extends);
  34. }
  35. foreach ($node->implements as &$interface) {
  36. $interface = $this->resolveClassName($interface);
  37. }
  38. $this->addNamespacedName($node);
  39. } elseif ($node instanceof PHPParser_Node_Stmt_Interface) {
  40. foreach ($node->extends as &$interface) {
  41. $interface = $this->resolveClassName($interface);
  42. }
  43. $this->addNamespacedName($node);
  44. } elseif ($node instanceof PHPParser_Node_Stmt_Trait) {
  45. $this->addNamespacedName($node);
  46. } elseif ($node instanceof PHPParser_Node_Stmt_Function) {
  47. $this->addNamespacedName($node);
  48. } elseif ($node instanceof PHPParser_Node_Stmt_Const) {
  49. foreach ($node->consts as $const) {
  50. $this->addNamespacedName($const);
  51. }
  52. } elseif ($node instanceof PHPParser_Node_Expr_StaticCall
  53. || $node instanceof PHPParser_Node_Expr_StaticPropertyFetch
  54. || $node instanceof PHPParser_Node_Expr_ClassConstFetch
  55. || $node instanceof PHPParser_Node_Expr_New
  56. || $node instanceof PHPParser_Node_Expr_Instanceof
  57. ) {
  58. if ($node->class instanceof PHPParser_Node_Name) {
  59. $node->class = $this->resolveClassName($node->class);
  60. }
  61. } elseif ($node instanceof PHPParser_Node_Stmt_Catch) {
  62. $node->type = $this->resolveClassName($node->type);
  63. } elseif ($node instanceof PHPParser_Node_Expr_FuncCall
  64. || $node instanceof PHPParser_Node_Expr_ConstFetch
  65. ) {
  66. if ($node->name instanceof PHPParser_Node_Name) {
  67. $node->name = $this->resolveOtherName($node->name);
  68. }
  69. } elseif ($node instanceof PHPParser_Node_Stmt_TraitUse) {
  70. foreach ($node->traits as &$trait) {
  71. $trait = $this->resolveClassName($trait);
  72. }
  73. } elseif ($node instanceof PHPParser_Node_Param
  74. && $node->type instanceof PHPParser_Node_Name
  75. ) {
  76. $node->type = $this->resolveClassName($node->type);
  77. }
  78. }
  79. protected function resolveClassName(PHPParser_Node_Name $name) {
  80. // don't resolve special class names
  81. if (in_array((string) $name, array('self', 'parent', 'static'))) {
  82. return $name;
  83. }
  84. // fully qualified names are already resolved
  85. if ($name->isFullyQualified()) {
  86. return $name;
  87. }
  88. // resolve aliases (for non-relative names)
  89. if (!$name->isRelative() && isset($this->aliases[$name->getFirst()])) {
  90. $name->setFirst($this->aliases[$name->getFirst()]);
  91. // if no alias exists prepend current namespace
  92. } elseif (null !== $this->namespace) {
  93. $name->prepend($this->namespace);
  94. }
  95. return new PHPParser_Node_Name_FullyQualified($name->parts, $name->getAttributes());
  96. }
  97. protected function resolveOtherName(PHPParser_Node_Name $name) {
  98. // fully qualified names are already resolved and we can't do anything about unqualified
  99. // ones at compiler-time
  100. if ($name->isFullyQualified() || $name->isUnqualified()) {
  101. return $name;
  102. }
  103. // resolve aliases for qualified names
  104. if ($name->isQualified() && isset($this->aliases[$name->getFirst()])) {
  105. $name->setFirst($this->aliases[$name->getFirst()]);
  106. // prepend namespace for relative names
  107. } elseif (null !== $this->namespace) {
  108. $name->prepend($this->namespace);
  109. }
  110. return new PHPParser_Node_Name_FullyQualified($name->parts, $name->getAttributes());
  111. }
  112. protected function addNamespacedName(PHPParser_Node $node) {
  113. if (null !== $this->namespace) {
  114. $node->namespacedName = clone $this->namespace;
  115. $node->namespacedName->append($node->name);
  116. } else {
  117. $node->namespacedName = new PHPParser_Node_Name($node->name, $node->getAttributes());
  118. }
  119. }
  120. }