refactor(php): 重构 isset 和 empty 表达式解析逻辑

- 将 parseIsset 方法重构为只支持单个变量检查
- 添加 parseVarCheckExpr 通用方法处理 isset 和 empty 操作
- 移除 parseEmpty 方法中的重复代码逻辑
- 支持静态属性获取表达式的 isset 和 empty 检查
- 更新错误消息模板以反映正确的操作符名称
- 添加 isset-test.phpt 测试文件验证功能
- 扩展 empty-test.phpt 包含静态属性测试用例
pull/1/head
韩天峰 7 months ago
parent 0723e9f01f
commit c3eb2d2f3f
  1. 52
      src/Php/CompilerBase.php
  2. 5
      tests/aot/empty-test.phpt
  3. 18
      tests/aot/isset-test.phpt

@ -2679,43 +2679,31 @@ class CompilerBase extends \PhpAot\Core\Translator
return sprintf('%.' . $this->floatPrecision . 'g', $value);
}
protected function parseIsset(mixed $expr)
protected function parseIsset(mixed $expr): string
{
$vars = $expr->vars;
foreach ($vars as $var) {
if ($var instanceof Variable) {
return $this->hasVar($var->name) ? 'true' : 'false';
}
if ($var instanceof Node\Expr\ArrayDimFetch) {
return $this->parseIdentifier($var->var) . '.offsetExists(' . $this->parseIdentifier($var->dim) . ')';
}
if ($var instanceof Node\Expr\StaticPropertyFetch) {
$nativeProp = $this->findNativeStaticProperty($var, $class, $namespace);
if ($nativeProp) {
return 'true';
}
return 'php::hasStaticProperty(' . $this->identifierToStr($var->class) . ', ' . $this->identifierToStr($var->name) . ')';
}
if ($var instanceof Node\Expr\PropertyFetch) {
$prop = $var->name;
$object = $this->parseIdentifier($var->var);
if ($object === 'this_' and $this->isIdExpr($prop)) {
return $this->escapeBool($this->classDef->hasProperty($this->parseIdentifier($prop)));
}
return $object . '.propertyExists(' . $this->identifierToStr($prop) . ')';
}
abort($var);
if (count($vars) > 1) {
$this->fatalError($expr, 'Cannot check multiple variables with isset');
}
return $this->parseVarCheckExpr($vars[0], 'isset');
}
protected function parseEmpty(Node\Expr\Empty_ $expr): string
{
if ($this->isVarExpr($expr->expr)) {
return 'php::empty(' . $this->parseExpr($expr->expr) . ')';
return $this->parseVarCheckExpr($expr->expr, 'empty');
}
protected function parseVarCheckExpr(NodeAbstract $expr, string $op): string
{
if ($this->isVarExpr($expr)) {
if ($op === 'isset') {
return $this->hasVar($this->parseIdentifier($expr)) ? 'true' : 'false';
} else {
return 'php::' . $op . '(' . $this->parseExpr($expr) . ')';
}
}
$list = [];
$expr = $expr->expr;
while (true) {
if ($this->isArrayDimFetch($expr)) {
if ($expr->dim === null) {
@ -2726,16 +2714,22 @@ class CompilerBase extends \PhpAot\Core\Translator
} elseif ($this->isPropertyFetch($expr)) {
$name = $this->identifierToStr($expr->name);
$list[] = '{php::PropertyFetch, ' . self::TYPE_VAR . '(' . $name . ')}';
} elseif ($this->isStaticPropertyFetch($expr)) {
$var = $this->genTmpVarName();
$this->addLocalVar($var, self::TYPE_VAR);
$this->beforeStmtLines[] = $var . '=' . $this->parseStaticPropertyFetch($expr) . ';';
break;
} elseif ($this->isVarExpr($expr)) {
$var = $this->parseIdentifier($expr);
break;
} else {
$this->fatalError($expr, 'The empty() only supports variables, array fetch, and property read');
$this->fatalError($expr, 'The ' . $op . '() only supports variables, array fetch, and property read');
}
$expr = $expr->var;
}
$list = array_reverse($list);
return 'php::empty(' . $var . ', {' . implode(', ', $list) . '})';
$fn = $op === 'isset' ? 'exists' : 'empty';
return 'php::' . $fn . '(' . $var . ', {' . implode(', ', $list) . '})';
}
protected function parseCastArray(Node\Expr\Cast\Array_ $expr): string

@ -2,12 +2,17 @@
empty (linked expr)
--FILE--
<?php
include __DIR__ . '/static_property_test.inc';
$arr = array(
array(2, 2)
);
var_dump(empty(TestClass::$default_static_property));
var_dump(empty(TestClass::$default_static_property_not_exist));
var_dump(empty($arr[0][1]));
var_dump(empty($arr[0][1][2][3]->prop[4]));
?>
--EXPECT--
bool(false)
bool(true)
bool(false)
bool(true)

@ -0,0 +1,18 @@
--TEST--
isset (linked expr)
--FILE--
<?php
include __DIR__ . '/static_property_test.inc';
$arr = array(
array(2, 2)
);
var_dump(isset(TestClass::$default_static_property));
var_dump(isset(TestClass::$default_static_property_not_exist));
var_dump(isset($arr[0][1]));
var_dump(isset($arr[0][1][2][3]->prop[4]));
?>
--EXPECT--
bool(true)
bool(false)
bool(true)
bool(false)
Loading…
Cancel
Save