From 935aeb8b1b13272b1c1c40333a2c1cef9a0a75f7 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Mon, 27 Apr 2026 17:29:47 +0800 Subject: [PATCH] =?UTF-8?q?refactor(php):=20=E9=87=8D=E6=9E=84=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E8=B5=8B=E5=80=BC=E7=B1=BB=E5=9E=8B=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将复杂的类型检查条件判断提取到独立的 checkVarAssignExpr 方法中 - 移除 CompilerBase.php 中的冗长条件判断逻辑 - 在 MagicMethodDetector.php 的 __toString 检查中添加严格类型参数 - 添加 str.php 示例文件用于测试字符串类型转换 - 更新 myext/test.php 添加环境变量访问示例 - 在 Translator.php 中添加 clang-format 版本检测逻辑 --- examples/error/str.php | 20 +++++++++++++++ examples/myext/test.php | 7 ++++++ src/Php/CompilerBase.php | 43 +++++++++++++++++++++++++++------ src/Php/MagicMethodDetector.php | 2 +- src/Php/Translator.php | 5 ++++ 5 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 examples/error/str.php diff --git a/examples/error/str.php b/examples/error/str.php new file mode 100644 index 00000000..c83c38dd --- /dev/null +++ b/examples/error/str.php @@ -0,0 +1,20 @@ +a; + } +} +function test(string $a) +{ + var_dump($a); +} + +function main() +{ + $o = new TestObject(); + $o->a = "hello"; + test($o); +} + diff --git a/examples/myext/test.php b/examples/myext/test.php index b8b42c7b..7cb6f3f8 100644 --- a/examples/myext/test.php +++ b/examples/myext/test.php @@ -1,5 +1,12 @@ hasVar($var)) { $this->addLocalVar($var, $type); - } elseif (($this->getVarType($var) !== self::TYPE_VAR and $this->isTypedObject($var) and $type !== self::TYPE_OBJECT) - // 禁止字符串与数组互相转换,其他类型如对象可以使用 __toString() 协议转为字符串,整数和浮点型也可以转为字符串 - or ($this->getVarType($var) === self::TYPE_STR and $type === self::TYPE_ARRAY) - or ($this->getVarType($var) === self::TYPE_ARRAY and $type === self::TYPE_STR) - // 禁止对象转为数组 - or ($this->getVarType($var) === self::TYPE_ARRAY and $type === self::TYPE_OBJECT) - ) { - $this->fatalError($left, "Cannot re-assign variable `\${$var}` from " . $this->getVarType($var) . ' to ' . $type); + } else { + $this->checkVarAssignExpr($left, $this->getVarType($var), $type); } } } elseif ($this->isPropertyFetch($left) and !$left->getAttribute('nativeProperty')) { @@ -3411,6 +3405,8 @@ class CompilerBase extends \PhpAot\Core\Translator return $this->convertToRef($arg->value); } + $this->checkVarAssignExpr($arg, $argInfo->type, $type); + if ($argInfo->type === self::TYPE_OBJECT) { if ($this->isVarExpr($arg->value)) { $object = $this->parseVariable($arg->value); @@ -4730,6 +4726,37 @@ class CompilerBase extends \PhpAot\Core\Translator } } + protected function checkVarAssignExpr(NodeAbstract $left, string $toType, string $fromType): bool + { + if ($toType === self::TYPE_VAR or $fromType === self::TYPE_VAR) { + return true; + } + // 引用当前没有类型信息,按照 var 处理 + if ($toType === self::TYPE_REF or $fromType === self::TYPE_REF) { + return true; + } + if ($toType === self::TYPE_OBJECT and $fromType === self::TYPE_OBJECT) { + return true; + } + if ($toType === self::TYPE_ARRAY and $fromType === self::TYPE_ARRAY) { + return true; + } + if ($toType === self::TYPE_STR) { + if ($fromType === self::TYPE_STR) { + return true; + } + if (!$this->strictTypes) { + $this->warning($left, "Attempt to implicitly convert `$fromType` to `$toType`"); + return true; + } + } + // 原生类型可以互相转换,由 C++ 底层完成 + if ($this->isNativeType($toType) and $this->isNativeType($fromType)) { + return true; + } + $this->fatalError($left, "Cannot re-assign variable from `$fromType` to `$toType`"); + } + protected function mustNoCall(NodeAbstract $node): void { $nodeFinder = new NodeFinder(); diff --git a/src/Php/MagicMethodDetector.php b/src/Php/MagicMethodDetector.php index a038a45d..0d32ea02 100644 --- a/src/Php/MagicMethodDetector.php +++ b/src/Php/MagicMethodDetector.php @@ -32,7 +32,7 @@ trait MagicMethodDetector $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must take exactly 1 argument"); } } elseif ($nameLower == '__tostring') { - if (!$this->checkArgType($returnType, self::TYPE_STR)) { + if (!$this->checkArgType($returnType, self::TYPE_STR, false)) { $this->fatalError($v, 'Method ' . $this->class . "::{$name}() must return string"); } } elseif ($nameLower == '__serialize') { diff --git a/src/Php/Translator.php b/src/Php/Translator.php index c2dc9a2d..2721399c 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -225,6 +225,11 @@ class Translator extends Preprocessor $this->error("The `libphpx.so` is not found, please run `make` to build it"); } + $clangFormatVersion = shell_exec('clang-format --version'); + if (empty($clangFormatVersion)) { + $this->formatCode = false; + } + $files = $this->getFiles($path); // 应用 ignorePaths 过滤 if (!empty($this->ignorePaths)) {