diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index df5f3753..5b164d95 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -164,7 +164,7 @@ class CompilerBase extends \PhpAot\Core\Translator protected string $ldflags = ''; protected int $floatPrecision = 17; protected bool $debugInfo = true; - protected bool $printBacktraceOnError = false; + protected bool $printBacktraceOnError = true; protected bool $noLiteralStrings = false; protected string $file; protected string $dir; @@ -1289,7 +1289,10 @@ class CompilerBase extends \PhpAot\Core\Translator if ($rightClass) { if (!$this->hasVar($var)) { $this->addLocalVar($var, self::TYPE_OBJECT); - $this->addObject($var, $rightClass); + // TODO 返回值类型是一个接口,只能作为 var 变量,无法作为 TypedObject + if (!$this->hasInterface($rightClass)) { + $this->addObject($var, $rightClass); + } } elseif ($this->isTypedObject($var)) { $leftClass = $this->getObjectType($var); // 对象的类不一致,不能互相赋值,必须使用 objval() 对齐类型 @@ -1579,8 +1582,8 @@ class CompilerBase extends \PhpAot\Core\Translator $objectClass = $this->detectClassOfExpr($v->expr); $returnClass = $this->getReturnClass(); if ($returnClass) { - if (!$objectClass) { - // TODO 返回值的类型无法确定,需要插入动态类型检测代码 + if (!$objectClass or $this->hasInterface($objectClass)) { + // TODO 返回值的类型无法确定,或者是一个接口,无法继承关系,需要插入动态类型检测代码 } elseif (!$this->isInheritedFrom($objectClass, $returnClass)) { $this->fatalError($v, 'The return type is `' . $returnClass . '`, cannot return an instance of `' . $objectClass . '`'); } @@ -1709,6 +1712,11 @@ class CompilerBase extends \PhpAot\Core\Translator return array_key_exists($this->escapeClass($name), $this->classes); } + protected function hasInterface(string $name): bool + { + return array_key_exists($this->escapeClass($name), $this->interfaces); + } + protected function checkFunction(string $name): void { // 在预处理阶段检测到函数声明,但是未定义,说明在当前文件,但是顺序错误 @@ -3259,24 +3267,35 @@ class CompilerBase extends \PhpAot\Core\Translator protected function isInheritedFrom(string $class, string $expected): bool { $internal = ($this->isInternalClass($expected) or $this->isInternalInterface($expected)); - + $isInterface = $this->hasInterface($expected); + // 类不存在,说明这是一个动态类,跳过静态检查,需要运行时检查 + if (!$this->hasClass($class)) { + return true; + } + $classDef = $this->getClass($class); while (true) { - if (strcasecmp($class, $expected) === 0) { - return true; - } - if (!$this->hasClass($class)) { - // 原生类继承自一个内置类,例如: UserError extends Exception ,然后 $expected 预期是 Throwable - // 这种情况,需要使用 ZendVM 获取继承关系 - if ($this->isInternalClass($class) and $internal) { - return $class === $expected or is_subclass_of($class, $expected); + if ($isInterface) { + if ($classDef->implements and in_array($expected, $classDef->implements)) { + return true; + } + } else { + if (strcasecmp($class, $expected) === 0) { + return true; + } + if (!$this->hasClass($class)) { + // 原生类继承自一个内置类,例如: UserError extends Exception ,然后 $expected 预期是 Throwable + // 这种情况,需要使用 ZendVM 获取继承关系 + if ($this->isInternalClass($class) and $internal) { + return $class === $expected or is_subclass_of($class, $expected); + } + return false; } - return false; } - $classDef = $this->getClass($class); if (!$classDef->extends) { return false; } $class = $classDef->extends; + $classDef = $this->getClass($class); } } diff --git a/src/Php/Translator.php b/src/Php/Translator.php index f91099ea..7cf693fe 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -1450,11 +1450,11 @@ class Translator extends Preprocessor protected function parseInterface(Node\Stmt\Interface_ $v): void { - $name = $this->parseIdentifier($v->name); - $this->interface = $name; - $this->interfaceDef = new InterfaceDef($name, $this->namespace); - $interfaceName = $this->interfaceDef->getNamespacedName(); - $this->interfaces[$interfaceName] = $this->interfaceDef; + $name = $this->parseIdentifier($v->name); + $this->interface = $name; + $this->interfaceDef = new InterfaceDef($name, $this->namespace); + $interfaceName = $this->interfaceDef->getNamespacedName(); + $this->interfaces[$this->escapeClass($interfaceName)] = $this->interfaceDef; $this->interfacesDefineInFile[$interfaceName] = $this->interfaceDef; } diff --git a/tests/aot/type_hits/004.phpt b/tests/aot/type_hits/004.phpt new file mode 100644 index 00000000..50cab4fa --- /dev/null +++ b/tests/aot/type_hits/004.phpt @@ -0,0 +1,33 @@ +--TEST-- +type hits +--FILE-- +send('Hello World', 'foo@bar'); +} + +function main() +{ + $obj = create_transport(); + configure_transport($obj); +} +?> +--EXPECT-- +string(11) "Hello World" +string(7) "foo@bar" diff --git a/tests/aot/type_hits/005.phpt b/tests/aot/type_hits/005.phpt new file mode 100644 index 00000000..a1f8faff --- /dev/null +++ b/tests/aot/type_hits/005.phpt @@ -0,0 +1,49 @@ +--TEST-- +type hits +--FILE-- +send('Hello World', 'foo@bar'); + } +} + +function main() +{ + $baz = new Baz; + $obj = $baz->create_transport(); + $foo = new FooB; + $foo->configure($obj); +} +} +?> +--EXPECT-- +string(11) "Hello World" +string(7) "foo@bar"