From d49d8578c5488012f5349e2e773a915af5cb6361 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Fri, 27 Mar 2026 12:43:08 +0800 Subject: [PATCH] =?UTF-8?q?feat(php):=20=E6=B7=BB=E5=8A=A0PHP=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E5=99=A8=E6=96=B9=E6=B3=95=E8=B0=83=E7=94=A8=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现了Expr_MethodCall节点的类型检测逻辑 - 添加了方法调用返回类型的反射检测功能 - 更新了方法调用的解析实现,使用call替换exec方法 - 移除了不再需要的objectWrappers相关代码 - 优化了对象转换和类型检查的处理流程 - 在Reflection类中添加了getMethodReturnType方法 - 改进了方法调用参数解析和执行的逻辑处理 --- src/Php/CompilerBase.php | 93 ++++++++++++++++++----------- src/Php/Context/FunctionContext.php | 7 --- src/Php/Reflection.php | 13 ++++ src/cpp/php_aot_helper.h | 7 --- 4 files changed, 70 insertions(+), 50 deletions(-) diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 235e85fd..59dc5fe3 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -1779,11 +1779,27 @@ class CompilerBase extends \PhpAot\Core\Translator } break; case 'Expr_FuncCall': - $name = $this->parseIdentifier($expr->name); - if ($this->hasNativeFunction($name)) { - return $this->getNativeFunction($name)->returnType; + if ($this->isNameExpr($expr->name)) { + $name = $this->parseIdentifier($expr->name); + if ($this->hasNativeFunction($name)) { + return $this->getNativeFunction($name)->returnType; + } + return $this->detectFuncCallReturnType($name); } - return $this->detectFuncCallReturnType($name); + break; + case 'Expr_MethodCall': + if ($this->isVarExpr($expr->var) and $this->isNamedMethod($expr->name)) { + $object = $this->parseIdentifier($expr->var); + $method = $this->parseIdentifier($expr->name); + $nativeFunc = $this->findNativeMethod($expr, $object, $method); + if ($nativeFunc) { + return $this->nativeFunctions[$nativeFunc]->returnType; + } + if ($this->isTypedObject($object)) { + return $this->detectMethodCallReturnType($this->getObjectType($object), $method); + } + } + break; case 'Expr_New': return self::TYPE_OBJECT; case 'Expr_Assign': @@ -2909,7 +2925,7 @@ class CompilerBase extends \PhpAot\Core\Translator protected function parseClone(Node\Expr\Clone_ $expr): string { - return 'php::clone('.$this->parseExpr($expr->expr).')'; + return 'php::clone(' . $this->parseExpr($expr->expr) . ')'; } protected function parseInstanceof(Node\Expr\Instanceof_ $expr): string @@ -3059,6 +3075,10 @@ class CompilerBase extends \PhpAot\Core\Translator return $this->convertToRef($arg->value); } + if ($argInfo->type === self::TYPE_OBJECT) { + return $this->convertObjectExpr($expr); + } + return $this->convertExprType($expr, $argInfo->type, $type); } @@ -3568,6 +3588,15 @@ class CompilerBase extends \PhpAot\Core\Translator return self::TYPE_VAR; } + protected function detectMethodCallReturnType(string $class, string $method): string + { + $returnType = Reflection::getMethodReturnType($class, $method); + if ($returnType) { + return $this->getTypeFromZendType($returnType); + } + return self::TYPE_VAR; + } + protected function convertExprFromType(string $type, string $expr): string { if ($type === self::TYPE_FLOAT) { @@ -3592,22 +3621,6 @@ class CompilerBase extends \PhpAot\Core\Translator return $expr; } - protected function convertToObject(NodeAbstract $object): string - { - $id = $this->parseIdentifier($object); - if ($this->isVarExpr($object)) { - if ($this->getVarType($id) === self::TYPE_OBJECT) { - return $id; - } - if (!isset($this->context->objectWrappers[$id])) { - $this->context->objectWrappers[$id] = $this->addTmpVar(self::TYPE_OBJECT); - } - return 'php_get_object_wrap(' . $this->context->objectWrappers[$id] . ', ' . $id . ')'; - } else { - return self::TYPE_OBJECT . '(' . $id . ')'; - } - } - protected function convertToRef(NodeAbstract $expr): string { $this->checkLeftValue($expr); @@ -3651,18 +3664,15 @@ class CompilerBase extends \PhpAot\Core\Translator protected function parseMethodCall(Node\Expr\MethodCall $expr): string { + $class = ''; + $object = $this->parseIdentifier($expr->var); if ($this->isVarExpr($expr->var)) { - $var = $this->parseIdentifier($expr->var); - if (!$this->hasVar($var)) { + if (!$this->hasVar($object)) { $this->errorUndefinedVariable($expr->var); } - } - - $object = $this->convertToObject($expr->var); - if ($this->isTypedObject($object)) { - $class = $this->getObjectType($object); - } else { - $class = ''; + if ($this->isTypedObject($object)) { + $class = $this->getObjectType($object); + } } $dynamicCall = false; @@ -3699,10 +3709,10 @@ class CompilerBase extends \PhpAot\Core\Translator } if (empty($expr->args)) { - return $object . '.exec(' . $methodPtr . ')'; + return $object . '.call(' . $methodPtr . ')'; } try { - return $object . '.exec(' . $methodPtr . ', ' . $this->parseCallArgs($expr->args, $funcName, $class) . ')'; + return $object . '.call(' . $methodPtr . ', ' . $this->parseCallArgs($expr->args, $funcName, $class) . ')'; } catch (PlaceHolder) { return $this->genPlaceHolder($this->genArray([$object, $method])); } @@ -3962,10 +3972,16 @@ class CompilerBase extends \PhpAot\Core\Translator protected function parseThrow(mixed $expr): string { - if (!$this->isVarExpr($expr->expr) and $expr->expr->getType() != self::EXPR_NEW) { - $ex = $this->convertToObject($expr->expr); - } else { + if ($this->isNewExpr($expr->expr)) { + $ex = $this->parseExpr($expr->expr); + } elseif ($this->isVarExpr($expr->expr)) { $ex = $this->parseIdentifier($expr->expr); + if ($this->getVarType($ex) != self::TYPE_OBJECT) { + goto _to_object; + } + } else { + _to_object: + $ex = $this->convertObjectExpr($expr->expr); } return 'php::throwException(' . $ex . ')'; } @@ -4252,6 +4268,11 @@ class CompilerBase extends \PhpAot\Core\Translator protected function parseNativeMethodCall(string $object, string $nativeFunc, array $args): string { + if ($this->getVarType($object) != self::TYPE_OBJECT) { + $tmpVar = $this->genTmpVarName(); + $this->context->beforeStmtLines[] = self::TYPE_OBJECT . ' ' . $tmpVar . ' = ' . $object . ';'; + $object = $tmpVar; + } if (count($args) === 0) { return self::PREFIX . $nativeFunc . '(' . $object . ')'; } @@ -4471,7 +4492,7 @@ class CompilerBase extends \PhpAot\Core\Translator $code .= $this->getIndent() . "{$tmpVar} = {$object}.attr({$item[1]}, {$update});"; } else { $args = $this->parseCallArgs($item[2]); - $code .= $this->getIndent() . "{$tmpVar} = {$object}.exec({$item[1]}, {$args});"; + $code .= $this->getIndent() . "{$tmpVar} = {$object}.call({$item[1]}, {$args});"; } $object = $tmpVar; } diff --git a/src/Php/Context/FunctionContext.php b/src/Php/Context/FunctionContext.php index c06b37f3..e3cad312 100644 --- a/src/Php/Context/FunctionContext.php +++ b/src/Php/Context/FunctionContext.php @@ -16,12 +16,6 @@ class FunctionContext public array $objects = []; public array $localVars = []; public array $staticVars = []; - - /** - * @var array - */ - public array $objectWrappers = []; - /** * @var array */ @@ -44,7 +38,6 @@ class FunctionContext $this->staticVars = []; $this->arguments = []; $this->objects = []; - $this->objectWrappers = []; $this->ceWrappers = []; $this->tmpVarIndex = 0; $this->inLoop = false; diff --git a/src/Php/Reflection.php b/src/Php/Reflection.php index 25b4b5bd..2158e8ac 100644 --- a/src/Php/Reflection.php +++ b/src/Php/Reflection.php @@ -136,4 +136,17 @@ class Reflection } return $class->hasMethod($method); } + + public static function getMethodReturnType(string $class, string $method): ?string + { + $class = self::getClass($class); + if (!$class) { + return null; + } + if (!$class->hasMethod($method)) { + return null; + } + $method = $class->getMethod($method); + return $method->getReturnType() ? $method->getReturnType()->getName() : null; + } } diff --git a/src/cpp/php_aot_helper.h b/src/cpp/php_aot_helper.h index ad039bcc..eb849455 100644 --- a/src/cpp/php_aot_helper.h +++ b/src/cpp/php_aot_helper.h @@ -23,10 +23,3 @@ extern void php_restore_scope(php::Scope &ori_scope); static inline auto php_get_create_object_fn(zend_class_entry *ce) { return ce->create_object ? ce->create_object : zend_objects_new; } - -static inline php::Object &php_get_object_wrap(php::Object &obj, php::Var &var) { - if (UNEXPECTED(obj.isNull())) { - obj = var; - } - return obj; -}