context->localVars[$name] = $type; } protected function registerStdType(string $key): int { if (isset($this->stdTypeMap[$key])) { return $this->stdTypeMap[$key]; } $typeId = count($this->stdTypeMap) + 1; $this->stdTypeMap[$key] = $typeId; return $typeId; } protected function addTmpVar(string $type): string { $var = $this->genTmpVarName(); $this->addLocalVar($var, $type); return $var; } protected function addStaticVar(Variable $var, string $name, string $type): string { if ($this->hasVar($name)) { $this->fatalError($var, 'Duplicate variable `$' . $var->name . '`'); } $this->context->staticVars[$name] = $type; // 静态变量实际上是一个全局变量的引用 $globalVar = $this->escapeStaticVar($name); $this->addGlobalVar($globalVar, $type); return $globalVar; } protected function hasArgument(string $name): bool { return isset($this->context->arguments[$name]); } protected function addArgument(string $name, string $type): void { $this->context->arguments[$name] = $type; $this->addLocalVar($name, $type); } protected function addLiteralString(string $value): int { $index = $this->literalStringIndex++; $this->literalStrings[$value] = $index; return $index; } protected function addGlobalVar(string $name, string $type): void { $this->globalVars[$name] = $type; } protected function addScopeGlobalVar(string $name, string $type): void { $this->context->globalVars[$name] = $type; } protected function addObject(string $name, string $class): void { // Interfaces have no concrete method body for native calls. Abstract classes may have concrete methods. if ($this->isInterface($class)) { $this->context->declaredObjects[$name] = $class; } elseif ($this->isNativeClass($class) or $this->isInternalClass($class)) { $this->context->objects[$name] = $class; } } protected function hasVar(string $name): bool { return $this->hasLocalVar($name) || $this->hasStaticVar($name) || $this->hasScopeGlobalVar($name) || $this->isSuperGlobal($name); } protected function hasLocalVar(string $name): bool { return isset($this->context->localVars[$name]); } protected function hasObjectPropVar(string $name): bool { return isset($this->context->objectProps[$name]); } protected function addFunction(string $name, FunctionDef $functionDef): void { $this->symbols->putFunction($this->escapeFunction($name), $functionDef); } /** * @param string $name 必须传入带有完整命名空间的类名,将会自动转义为 native name */ protected function hasFunction(string $name): bool { return $this->symbols->hasFunction($this->escapeFunction($name)); } protected function getFunction(string $name): FunctionDef { return $this->symbols->function($this->escapeFunction($name)); } protected function addClass(string $name, ClassDef $classDef): void { $this->symbols->putClass($this->escapeClass($name), $classDef); } protected function getClass(string $name): ClassDef { return $this->symbols->class($this->escapeClass($name)); } public function getClassDef(string $name): ?ClassDef { return $this->symbols->findClass($this->escapeClass($name)); } public function getParentClass(string $class): string { return $this->symbols->parent(strtolower(ltrim($class, '\\'))); } protected function hasClass(string $name): bool { return $this->symbols->hasClass($this->escapeClass($name)); } protected function hasInterface(string $name): bool { return $this->symbols->hasInterface($this->escapeClass($name)); } protected function getInterface(string $name): InterfaceDef { return $this->symbols->interface($this->escapeClass($name)); } protected function checkFunction(string $name): void { // 在预处理阶段检测到函数声明,但是未定义,说明在当前文件,但是顺序错误 // 跳过,稍后再处理 if (isset($this->symbolDeclInFile[$name]) and $this->symbolDeclInFile[$name] === $this->file and !$this->hasFunction($name)) { $this->redoAfterDeclare[$name] = true; throw new Skip(); } } }