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;
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;
}

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

@ -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;
}
}

@ -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;
}

Loading…
Cancel
Save