diff --git a/examples/extends2/A0.php b/examples/extends2/A0.php new file mode 100644 index 00000000..1cadcdca --- /dev/null +++ b/examples/extends2/A0.php @@ -0,0 +1,6 @@ +bar(); + } + + public function bar() { + echo "C0\n"; + } +} \ No newline at end of file diff --git a/examples/extends2/main.php b/examples/extends2/main.php new file mode 100644 index 00000000..f9863023 --- /dev/null +++ b/examples/extends2/main.php @@ -0,0 +1,9 @@ +run(); +} \ No newline at end of file diff --git a/examples/simple.php b/examples/simple.php index ab330f01..225341b9 100644 --- a/examples/simple.php +++ b/examples/simple.php @@ -5,4 +5,10 @@ function main() { $newArray = []; $newArray[] = 1; var_dump($newArray); // [1, 1] -} \ No newline at end of file +} + +class Fo { + +} + +// // empty diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index b6c0ec53..fb0ee33c 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -1103,133 +1103,6 @@ class CompilerBase extends \PhpAot\Core\Translator } } - /** - * Build type-check descriptor array from UnionType or NullableType AST node. - * Returns ['check' => array, 'typeStr' => string] or empty check array if no check needed. - */ - /** - * Generate a C++ boolean expression for a single type descriptor entry. - */ - /** - * Generate C++ runtime type-check block for a function parameter with union/nullable type. - */ - /** - * Generate C++ runtime type-check block for a function return value with union/nullable type. - */ - /** - * @throws \Exception - */ - protected function parseFunction(Node\Stmt\Function_|Node\Stmt\ClassMethod $v): string - { - $this->resetFunction(); - $name = $this->getFunctionName($v); - $this->function = $this->parseIdentifier($v->name); - - if (!$this->hasFunction($name)) { - $this->fatalError($v, 'Function `' . $name . '` not found'); - } - $this->functionDef = $this->getFunction($name); - - // 类方法不要保存到 functions 中 - if ($this->methodDef) { - $this->methodDef->functionDef = $this->functionDef; - } else { - $this->functionDefineInFile[$name] = $this->functionDef; - } - - // stub 函数,没有函数的具体实现,只有声明,实现在 C++ 或者 .so 中定义 - if ($this->functionDef->stub) { - $this->resetFunction(); - return ''; - } - - if ($this->class) { - $this->addArgument('this_', self::TYPE_OBJECT); - } - foreach ($this->functionDef->argInfoList as $argInfo) { - $this->addArgument($argInfo->name, $argInfo->type); - if ($argInfo->class) { - $this->addObject($argInfo->name, $argInfo->class); - } - } - - // Build SSA/e-SSA analysis for this function - if ($v->stmts) { - $this->context->ssaBuilder = new SsaBuilder($v->stmts, $this->functionDef->argInfoList); - $this->context->ssaBuilder->build(); - // Narrow local variable types based on SSA analysis - $this->optimizeVarTypes(); - // Analyze object stability for property reference hoisting - $this->optimizeObjectProps(); - } - - $stmts = ''; - if ($v->stmts) { - $this->indentLevel++; - try { - $stmts = $this->parseStmts($v->stmts); - if (!$this->isReturnStmtInLastLine($v->stmts)) { - $stmts .= $this->genReturnCode(); - } - } catch (Skip) { - $this->climate->cyan('Skip function ' . $name); - } - $this->indentLevel--; - } else { - $stmts = $this->genReturnCode(); - } - - $functionDeclCode = $this->getReturnType() . ' ' . self::PREFIX . $name . '('; - if ($this->class) { - $functionDeclCode .= self::TYPE_OBJECT . ' &this_'; - if ($this->functionDef->params) { - $functionDeclCode .= ', '; - } - } - $functionDeclCode .= $this->functionDef->params . ')'; - - $code = $functionDeclCode . ' {' . PHP_EOL; - $this->indentLevel++; - $code .= $this->genScopeVarDecl(); - $code .= "\n"; - // Constructor Property Promotion - foreach ($this->functionDef->argInfoList as $argInfo) { - if (!$argInfo->property) { - continue; - } - $code .= $this->genPropertyPromotion($argInfo); - } - // Runtime union/nullable parameter type checks - foreach ($this->functionDef->argInfoList as $i => $argInfo) { - if (!empty($argInfo->typeCheck)) { - $code .= $this->genUnionParamCheck($argInfo, $i); - } - } - $this->indentLevel--; - // 构建 PHP 级别的函数名用于 debug backtrace - if ($this->class) { - $debugName = $this->class . '::' . $this->function; - } else { - $debugName = $this->function; - if ($this->namespace) { - $debugName = $this->namespace . '\\' . $debugName; - } - } - $code .= $this->genDebugInfo(null, $debugName, $v->getStartLine()); - - // 函数中存在动态调用的函数,需要在运行时动态切换作用域 - if ($this->methodDef and $this->methodDef->hasDynamicCall) { - $code .= $this->genScopeSwitchCode(); - } - - $code .= $stmts; - $code .= "}\n"; - - $this->resetFunction(); - - return $code; - } - protected function writeLog($msg): void { if ($this->verbose) { diff --git a/src/Php/Preprocessor.php b/src/Php/Preprocessor.php index 6a82dfec..e0ede516 100644 --- a/src/Php/Preprocessor.php +++ b/src/Php/Preprocessor.php @@ -620,21 +620,6 @@ class Preprocessor extends CompilerBase } } - $fullClassName = $this->getFullClassName(); - $fullMethodName = $fullClassName . '::' . $this->method; - $this->classMethodOverride[strtolower($fullMethodName)] = false; - // 查找父类是否有同名方法,递归查找 - $fullClassNameLower = strtolower($fullClassName); - - while (isset($this->classExtends[$fullClassNameLower])) { - $parentClass = $this->classExtends[$fullClassNameLower]; - $parentMethodLower = strtolower($parentClass . '::' . $v->name); - // 父类有同名方法,子类覆盖了父类方法,这种情况不能直接使用 C++ 函数,而是使用 ZendVM 动态调用 - if (isset($this->classMethodOverride[$parentMethodLower])) { - $this->classMethodOverride[$parentMethodLower] = true; - } - $fullClassNameLower = strtolower($parentClass); - } $this->resetMethod(); } diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 17fc3e29..bfddf59b 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -9,6 +9,7 @@ namespace PhpAot\Php; use MJS\TopSort\Implementations\StringSort; +use PhpAot\Php\Analysis\SsaBuilder; use PhpAot\Php\Entity\ClassDef; use PhpAot\Php\Entity\ClassLikeDef; use PhpAot\Php\Entity\ConstantDef; @@ -17,6 +18,7 @@ use PhpAot\Php\Entity\InterfaceDef; use PhpAot\Php\Entity\MethodDef; use PhpAot\Php\Entity\PropertyDef; use PhpAot\Php\Exception\Redo; +use PhpAot\Php\Exception\Skip; use PhpAot\Php\Exception\SyntaxError; use PhpAot\Php\Exception\Unsupported; use PhpAot\Php\Generator\ResourceFileGenerator; @@ -2139,6 +2141,133 @@ CODE; return $code; } + /** + * Build type-check descriptor array from UnionType or NullableType AST node. + * Returns ['check' => array, 'typeStr' => string] or empty check array if no check needed. + */ + /** + * Generate a C++ boolean expression for a single type descriptor entry. + */ + /** + * Generate C++ runtime type-check block for a function parameter with union/nullable type. + */ + /** + * Generate C++ runtime type-check block for a function return value with union/nullable type. + */ + /** + * @throws \Exception + */ + protected function parseFunction(Node\Stmt\Function_|Node\Stmt\ClassMethod $v): string + { + $this->resetFunction(); + $name = $this->getFunctionName($v); + $this->function = $this->parseIdentifier($v->name); + + if (!$this->hasFunction($name)) { + $this->fatalError($v, 'Function `' . $name . '` not found'); + } + $this->functionDef = $this->getFunction($name); + + // 类方法不要保存到 functions 中 + if ($this->methodDef) { + $this->methodDef->functionDef = $this->functionDef; + } else { + $this->functionDefineInFile[$name] = $this->functionDef; + } + + // stub 函数,没有函数的具体实现,只有声明,实现在 C++ 或者 .so 中定义 + if ($this->functionDef->stub) { + $this->resetFunction(); + return ''; + } + + if ($this->class) { + $this->addArgument('this_', self::TYPE_OBJECT); + } + foreach ($this->functionDef->argInfoList as $argInfo) { + $this->addArgument($argInfo->name, $argInfo->type); + if ($argInfo->class) { + $this->addObject($argInfo->name, $argInfo->class); + } + } + + // Build SSA/e-SSA analysis for this function + if ($v->stmts) { + $this->context->ssaBuilder = new SsaBuilder($v->stmts, $this->functionDef->argInfoList); + $this->context->ssaBuilder->build(); + // Narrow local variable types based on SSA analysis + $this->optimizeVarTypes(); + // Analyze object stability for property reference hoisting + $this->optimizeObjectProps(); + } + + $stmts = ''; + if ($v->stmts) { + $this->indentLevel++; + try { + $stmts = $this->parseStmts($v->stmts); + if (!$this->isReturnStmtInLastLine($v->stmts)) { + $stmts .= $this->genReturnCode(); + } + } catch (Skip) { + $this->climate->cyan('Skip function ' . $name); + } + $this->indentLevel--; + } else { + $stmts = $this->genReturnCode(); + } + + $functionDeclCode = $this->getReturnType() . ' ' . self::PREFIX . $name . '('; + if ($this->class) { + $functionDeclCode .= self::TYPE_OBJECT . ' &this_'; + if ($this->functionDef->params) { + $functionDeclCode .= ', '; + } + } + $functionDeclCode .= $this->functionDef->params . ')'; + + $code = $functionDeclCode . ' {' . PHP_EOL; + $this->indentLevel++; + $code .= $this->genScopeVarDecl(); + $code .= "\n"; + // Constructor Property Promotion + foreach ($this->functionDef->argInfoList as $argInfo) { + if (!$argInfo->property) { + continue; + } + $code .= $this->genPropertyPromotion($argInfo); + } + // Runtime union/nullable parameter type checks + foreach ($this->functionDef->argInfoList as $i => $argInfo) { + if (!empty($argInfo->typeCheck)) { + $code .= $this->genUnionParamCheck($argInfo, $i); + } + } + $this->indentLevel--; + // 构建 PHP 级别的函数名用于 debug backtrace + if ($this->class) { + $debugName = $this->class . '::' . $this->function; + } else { + $debugName = $this->function; + if ($this->namespace) { + $debugName = $this->namespace . '\\' . $debugName; + } + } + $code .= $this->genDebugInfo(null, $debugName, $v->getStartLine()); + + // 函数中存在动态调用的函数,需要在运行时动态切换作用域 + if ($this->methodDef and $this->methodDef->hasDynamicCall) { + $code .= $this->genScopeSwitchCode(); + } + + $code .= $stmts; + $code .= "}\n"; + + $this->resetFunction(); + + return $code; + } + protected function parseClassMethod(Node\Stmt\ClassMethod $v, array &$methodCodes): void { $name = $this->getMethodName($v); @@ -2152,6 +2281,22 @@ CODE; $methodCodes[$name] = $this->parseFunction($v); } + $fullClassName = $this->getFullClassName(); + $fullMethodName = $fullClassName . '::' . $this->method; + $this->classMethodOverride[strtolower($fullMethodName)] = false; + // 查找父类是否有同名方法,递归查找 + $fullClassNameLower = strtolower($fullClassName); + + while (isset($this->classExtends[$fullClassNameLower])) { + $parentClass = $this->classExtends[$fullClassNameLower]; + $parentMethodLower = strtolower($parentClass . '::' . $v->name); + // 父类有同名方法,子类覆盖了父类方法,这种情况不能直接使用 C++ 函数,而是使用 ZendVM 动态调用 + if (isset($this->classMethodOverride[$parentMethodLower])) { + $this->classMethodOverride[$parentMethodLower] = true; + } + $fullClassNameLower = strtolower($parentClass); + } + $this->resetMethod(); }