refactor(php): 重构变量赋值类型检查逻辑

- 将复杂的类型检查条件判断提取到独立的 checkVarAssignExpr 方法中
- 移除 CompilerBase.php 中的冗长条件判断逻辑
- 在 MagicMethodDetector.php 的 __toString 检查中添加严格类型参数
- 添加 str.php 示例文件用于测试字符串类型转换
- 更新 myext/test.php 添加环境变量访问示例
- 在 Translator.php 中添加 clang-format 版本检测逻辑
pull/1/head
韩天峰 4 months ago
parent 3460c1e435
commit 935aeb8b1b
  1. 20
      examples/error/str.php
  2. 7
      examples/myext/test.php
  3. 43
      src/Php/CompilerBase.php
  4. 2
      src/Php/MagicMethodDetector.php
  5. 5
      src/Php/Translator.php

@ -0,0 +1,20 @@
<?php
class TestObject {
public string $a;
function __toString(): string
{
return $this->a;
}
}
function test(string $a)
{
var_dump($a);
}
function main()
{
$o = new TestObject();
$o->a = "hello";
test($o);
}

@ -1,5 +1,12 @@
<?php
function my_add(int $a, int $b): int
{
$env = $_ENV;
var_dump(count($env));
return $a + $b;
}
function main()
{
var_dump(my_add(1, 2));
}

@ -1377,14 +1377,8 @@ class CompilerBase extends \PhpAot\Core\Translator
}
if (!$this->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();

@ -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') {

@ -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)) {

Loading…
Cancel
Save