refactor(parser): 重构零值字面量检测逻辑

- 将 isZeroLiteral 方法从 BinaryOpTrait 移动到 CompilerBase 类中
- 为 isZeroLiteral 方法添加详细的文档注释说明其用途
- 添加 targetPlatform 配置选项支持交叉编译目标平台
- 修复对象属性测试用例中的数组索引访问功能
- 在 array_sum 和 array_product 测试中添加错误报告控制
pull/3/head
韩天峰 2 months ago
parent 8267ae2bf4
commit cba9990e80
  1. 38
      src/Php/CompilerBase.php
  2. 18
      src/Php/Parser/BinaryOpTrait.php
  3. 24
      tests/aot/object_property/007.phpt
  4. 1
      tests/std/array/007.phpt

@ -242,6 +242,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected string $cxxFlags = '';
protected string $cxxStd = 'c++17';
protected string $march = ''; // --march: target CPU instruction set (e.g. native, x86-64-v3)
protected string $targetPlatform = ''; // --target-platform: cross-compilation target triple (e.g. aarch64-linux-gnu)
protected string $ldflags = '';
protected array $linkLibs = []; // --link-lib / -l: user-specified libraries to link
protected array $linkPaths = []; // --link-path / -L: user-specified library search paths
@ -1207,14 +1208,42 @@ class CompilerBase extends \PhpAot\Core\Translator
$key = $this->parseIdentifier($expr);
if (str_starts_with($key, self::LITERAL_STRINGS)) {
$key = "{$key}.str()";
} elseif ($key === '0L' || $key === '0LL') {
// 0 在 C++ 中是一个特殊的值,存在二义性,既是空指针,也是整数,这会导致产生 ambiguous 错误
// 必须转为 php::zero 常量,保证作为 key 时正确匹配到 IntKeyMap
} elseif ($this->isZeroLiteral($expr)) {
$key = self::VALUE_ZERO;
}
return $key;
}
/**
* Check if a node is a literal zero value.
*
* Detects compile-time zero for two purposes:
* - Division-by-zero guard (any zero form: int, float, negated, numeric string)
* - C++ null pointer ambiguity guard: Scalar_Int(0) → 0L → nullptr → segfault
* when passed to functions with zend_string* overloads (setProperty, getProperty, etc.)
*/
protected function isZeroLiteral(NodeAbstract $expr): bool
{
if ($expr instanceof Node\Scalar\Int_) {
$result = $expr->value === 0;
return $result;
}
if ($expr instanceof Node\Scalar\Float_) {
$result = $expr->value == 0.0;
return $result;
}
if ($expr instanceof Expr\UnaryMinus || $expr instanceof Expr\UnaryPlus) {
$result = $this->isZeroLiteral($expr->expr);
return $result;
}
if ($expr instanceof Node\Scalar\String_) {
$value = trim($expr->value);
$result = $value !== '' && is_numeric($value) && (float) $value == 0.0;
return $result;
}
return false;
}
protected function parseIdentifier(NodeAbstract $expr): string
{
$type = $expr->getType();
@ -4655,6 +4684,9 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->isNameExpr($node) or $this->isIdExpr($node)) {
return $literal ? $this->getLiteralString($id) : $this->genCharPtr($id, true);
}
if ($this->isZeroLiteral($node)) {
return self::VALUE_ZERO;
}
return $id;
}

@ -362,24 +362,6 @@ trait BinaryOpTrait
}
}
protected function isZeroLiteral(NodeAbstract $expr): bool
{
if ($expr instanceof Node\Scalar\Int_) {
return $expr->value === 0;
}
if ($expr instanceof Node\Scalar\Float_) {
return $expr->value == 0.0;
}
if ($expr instanceof Expr\UnaryMinus || $expr instanceof Expr\UnaryPlus) {
return $this->isZeroLiteral($expr->expr);
}
if ($expr instanceof Node\Scalar\String_) {
$value = trim($expr->value);
return $value !== '' && is_numeric($value) && (float) $value == 0.0;
}
return false;
}
protected function parseBinaryOpMinus(Expr\BinaryOp\Minus $expr): string
{
return $this->parseBinaryOp($expr->left, $expr->right, '-');

@ -0,0 +1,24 @@
--TEST--
default array property
--FILE--
<?php
function main() {
$o = new stdClass();
$year = 1995;
$first = 'php';
$last = '.net';
$o->{0} = $year;
$o->{1} = $first;
$o->{2} = $last;
var_dump($o);
}
?>
--EXPECTF--
object(stdClass)#%d (3) {
["0"]=>
int(1995)
["1"]=>
string(3) "php"
["2"]=>
string(4) ".net"
}

@ -3,6 +3,7 @@ array_sum / array_product: type handling
--FILE--
<?php
function main() {
error_reporting(E_ALL & ~E_WARNING);
// Non-numeric strings contribute 0 as int (not float)
var_dump(array_sum([1, 2, "abc"]));
var_dump(array_product([1, 2, "abc"]));

Loading…
Cancel
Save