feat(php): 添加PHP编译器方法调用支持

- 实现了Expr_MethodCall节点的类型检测逻辑
- 添加了方法调用返回类型的反射检测功能
- 更新了方法调用的解析实现,使用call替换exec方法
- 移除了不再需要的objectWrappers相关代码
- 优化了对象转换和类型检查的处理流程
- 在Reflection类中添加了getMethodReturnType方法
- 改进了方法调用参数解析和执行的逻辑处理
pull/1/head
韩天峰 5 months ago
parent 7dd30e2908
commit d49d8578c5
  1. 93
      src/Php/CompilerBase.php
  2. 7
      src/Php/Context/FunctionContext.php
  3. 13
      src/Php/Reflection.php
  4. 7
      src/cpp/php_aot_helper.h

@ -1779,11 +1779,27 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
break; break;
case 'Expr_FuncCall': case 'Expr_FuncCall':
$name = $this->parseIdentifier($expr->name); if ($this->isNameExpr($expr->name)) {
if ($this->hasNativeFunction($name)) { $name = $this->parseIdentifier($expr->name);
return $this->getNativeFunction($name)->returnType; 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': case 'Expr_New':
return self::TYPE_OBJECT; return self::TYPE_OBJECT;
case 'Expr_Assign': case 'Expr_Assign':
@ -2909,7 +2925,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseClone(Node\Expr\Clone_ $expr): string 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 protected function parseInstanceof(Node\Expr\Instanceof_ $expr): string
@ -3059,6 +3075,10 @@ class CompilerBase extends \PhpAot\Core\Translator
return $this->convertToRef($arg->value); return $this->convertToRef($arg->value);
} }
if ($argInfo->type === self::TYPE_OBJECT) {
return $this->convertObjectExpr($expr);
}
return $this->convertExprType($expr, $argInfo->type, $type); return $this->convertExprType($expr, $argInfo->type, $type);
} }
@ -3568,6 +3588,15 @@ class CompilerBase extends \PhpAot\Core\Translator
return self::TYPE_VAR; 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 protected function convertExprFromType(string $type, string $expr): string
{ {
if ($type === self::TYPE_FLOAT) { if ($type === self::TYPE_FLOAT) {
@ -3592,22 +3621,6 @@ class CompilerBase extends \PhpAot\Core\Translator
return $expr; 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 protected function convertToRef(NodeAbstract $expr): string
{ {
$this->checkLeftValue($expr); $this->checkLeftValue($expr);
@ -3651,18 +3664,15 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseMethodCall(Node\Expr\MethodCall $expr): string protected function parseMethodCall(Node\Expr\MethodCall $expr): string
{ {
$class = '';
$object = $this->parseIdentifier($expr->var);
if ($this->isVarExpr($expr->var)) { if ($this->isVarExpr($expr->var)) {
$var = $this->parseIdentifier($expr->var); if (!$this->hasVar($object)) {
if (!$this->hasVar($var)) {
$this->errorUndefinedVariable($expr->var); $this->errorUndefinedVariable($expr->var);
} }
} if ($this->isTypedObject($object)) {
$class = $this->getObjectType($object);
$object = $this->convertToObject($expr->var); }
if ($this->isTypedObject($object)) {
$class = $this->getObjectType($object);
} else {
$class = '';
} }
$dynamicCall = false; $dynamicCall = false;
@ -3699,10 +3709,10 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
if (empty($expr->args)) { if (empty($expr->args)) {
return $object . '.exec(' . $methodPtr . ')'; return $object . '.call(' . $methodPtr . ')';
} }
try { try {
return $object . '.exec(' . $methodPtr . ', ' . $this->parseCallArgs($expr->args, $funcName, $class) . ')'; return $object . '.call(' . $methodPtr . ', ' . $this->parseCallArgs($expr->args, $funcName, $class) . ')';
} catch (PlaceHolder) { } catch (PlaceHolder) {
return $this->genPlaceHolder($this->genArray([$object, $method])); return $this->genPlaceHolder($this->genArray([$object, $method]));
} }
@ -3962,10 +3972,16 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseThrow(mixed $expr): string protected function parseThrow(mixed $expr): string
{ {
if (!$this->isVarExpr($expr->expr) and $expr->expr->getType() != self::EXPR_NEW) { if ($this->isNewExpr($expr->expr)) {
$ex = $this->convertToObject($expr->expr); $ex = $this->parseExpr($expr->expr);
} else { } elseif ($this->isVarExpr($expr->expr)) {
$ex = $this->parseIdentifier($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 . ')'; return 'php::throwException(' . $ex . ')';
} }
@ -4252,6 +4268,11 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseNativeMethodCall(string $object, string $nativeFunc, array $args): string 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) { if (count($args) === 0) {
return self::PREFIX . $nativeFunc . '(' . $object . ')'; return self::PREFIX . $nativeFunc . '(' . $object . ')';
} }
@ -4471,7 +4492,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$code .= $this->getIndent() . "{$tmpVar} = {$object}.attr({$item[1]}, {$update});"; $code .= $this->getIndent() . "{$tmpVar} = {$object}.attr({$item[1]}, {$update});";
} else { } else {
$args = $this->parseCallArgs($item[2]); $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; $object = $tmpVar;
} }

@ -16,12 +16,6 @@ class FunctionContext
public array $objects = []; public array $objects = [];
public array $localVars = []; public array $localVars = [];
public array $staticVars = []; public array $staticVars = [];
/**
* @var array<string, string>
*/
public array $objectWrappers = [];
/** /**
* @var array<string, string> * @var array<string, string>
*/ */
@ -44,7 +38,6 @@ class FunctionContext
$this->staticVars = []; $this->staticVars = [];
$this->arguments = []; $this->arguments = [];
$this->objects = []; $this->objects = [];
$this->objectWrappers = [];
$this->ceWrappers = []; $this->ceWrappers = [];
$this->tmpVarIndex = 0; $this->tmpVarIndex = 0;
$this->inLoop = false; $this->inLoop = false;

@ -136,4 +136,17 @@ class Reflection
} }
return $class->hasMethod($method); 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;
}
} }

@ -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) { static inline auto php_get_create_object_fn(zend_class_entry *ce) {
return ce->create_object ? ce->create_object : zend_objects_new; 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;
}

Loading…
Cancel
Save