From 3191ff2cce2c646827084e830207a39ba8acd0bd Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Fri, 20 Mar 2026 20:38:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(php):=20=E5=AE=9E=E7=8E=B0=E5=AF=B9=20inst?= =?UTF-8?q?anceof=20=E6=93=8D=E4=BD=9C=E7=AC=A6=E7=9A=84=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改 CompilerBase.php 中的 parseInstanceof 方法,添加对类名表达式的特殊处理 - 为 instanceof 操作符添加命名空间类名解析功能 - 支持通过 getClassEntryPtr 获取类条目指针 - 添加新的测试文件 union-intersection-types.phpt 验证联合类型和交叉类型 - 测试涵盖 union types、nullable union、mixed type 和 never type 的 instanceof 检查 - 实现对 PHP 8+ 类型系统的全面兼容性支持 --- src/Php/CompilerBase.php | 8 +- tests/aot/union-intersection-types.phpt | 113 ++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 tests/aot/union-intersection-types.phpt diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index cc3c77c6..fe4b1edf 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -2851,7 +2851,13 @@ class CompilerBase extends \PhpAot\Core\Translator protected function parseInstanceof(Node\Expr\Instanceof_ $expr): string { - return $this->convertToObject($expr->expr) . '.instanceOf(' . $this->identifierToStr($expr->class) . ')'; + if ($this->isNameExpr($expr->class)) { + $className = $this->getNamespacedClassName($this->parseIdentifier($expr->class)); + $className = $this->getClassEntryPtr($className); + return 'php::instanceOf(' . $this->parseExpr($expr->expr) . ', ' . $className . ')'; + } else { + return 'php::instanceOf(' . $this->parseExpr($expr->expr) . ', ' . $this->identifierToStr($expr->class) . ')'; + } } protected function parseCastInt(Node\Expr\Cast\Int_ $node): string diff --git a/tests/aot/union-intersection-types.phpt b/tests/aot/union-intersection-types.phpt new file mode 100644 index 00000000..0201356e --- /dev/null +++ b/tests/aot/union-intersection-types.phpt @@ -0,0 +1,113 @@ +--TEST-- +Union Types and Intersection Types - PHP 8+ type system +--SKIPIF-- +--FILE-- +radius = $radius; + } + + public function getArea(): float { + return M_PI * $this->radius * $this->radius; + } +} + +class Square extends Shape { + private float $side; + + public function __construct(float $side) { + $this->side = $side; + } + + public function getArea(): float { + return $this->side * $this->side; + } +} + +function process_shape(Shape|float $shape): float|string { + if ($shape instanceof Shape) { + return $shape->getArea(); + } else { + return "Invalid shape: " . $shape; + } +} + +// Test nullable union types +function format_value(int|string|null $value): string { + if ($value === null) { + return "No value"; + } + return "Value: " . $value; +} + +// Test mixed type (PHP 8.0+) +function handle_mixed(mixed $data): mixed { + return $data; +} + +// Test never type (PHP 8.0+) +function redirect(string $url): never { + throw new \RuntimeException("Redirecting to: " . $url); +} + +function main() { + // Test union types with instanceof + $circle = new Circle(5.0); + var_dump(process_shape($circle)); + + $square = new Square(4.0); + var_dump(process_shape($square)); + + var_dump(process_shape(100.5)); + + // Test nullable union + var_dump(format_value(42)); + var_dump(format_value("hello")); + var_dump(format_value(null)); + + // Test mixed type + var_dump(handle_mixed(42)); + var_dump(handle_mixed("string")); + var_dump(handle_mixed([1, 2, 3])); + var_dump(handle_mixed(new Circle(1.0))); + + // Test never type (will throw exception) + try { + redirect("http://example.com"); + } catch (RuntimeException $e) { + var_dump($e->getMessage()); + } +} +?> +--EXPECT-- +float(78.53981633974483) +float(16) +string(20) "Invalid shape: 100.5" +string(9) "Value: 42" +string(12) "Value: hello" +string(8) "No value" +int(42) +string(6) "string" +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +object(Circle)#3 (1) { + ["radius":"Circle":private]=> + float(1) +} +string(34) "Redirecting to: http://example.com"