fix(parser): optimize concat assignment and ternary expression handling

- Simplified concat assignment logic by checking for Concat instance directly instead of flattening
- Changed SelectionExpressionTrait to use parseExprAsValue for ternary branches
- Added proper handling of void branch conversion to null in ternary expressions
- Added tests for concat assignment to inherited properties
- Added tests for ternary expressions with void branches and side effects
pull/40/head
韩天峰 1 month ago
parent 9d29aa7a3f
commit 2d4a1b8bb0
  1. 4
      src/Parser/AssignOpTrait.php
  2. 5
      src/Parser/SelectionExpressionTrait.php
  3. 29
      tests/compiler/operator/concat-assign-inherited-property.phpt
  4. 48
      tests/compiler/operator/ternary-void-branches.phpt

@ -583,9 +583,7 @@ trait AssignOpTrait
}
if ($this->isAssignOpConcat($op)) {
$items = [];
$this->flattenConcatExpr($node->expr, $items);
if (count($items) === 1) {
if (!($node->expr instanceof Expr\BinaryOp\Concat)) {
return $var . '.append(' . $this->parseExprAsValue($node->expr) . ')';
}
return $var . ' = php::toString(' . $this->parseFlattenedConcat($node->expr, [$var]) . ')';

@ -25,7 +25,7 @@ trait SelectionExpressionTrait
[$cond, $condBeforeStmts, $condAfterStmts] = $this->parseExprWithCapturedStmts($expr->cond);
$ifBeforeStmtCount = count($this->context->beforeStmtLines);
$ifAfterStmtCount = count($this->context->afterStmtLines);
$if = $this->parseExpr($expr->if);
$if = $this->parseExprAsValue($expr->if);
$ifBeforeStmts = array_slice($this->context->beforeStmtLines, $ifBeforeStmtCount);
$ifAfterStmts = array_slice($this->context->afterStmtLines, $ifAfterStmtCount);
$this->context->beforeStmtLines = array_slice($this->context->beforeStmtLines, 0, $ifBeforeStmtCount);
@ -33,7 +33,7 @@ trait SelectionExpressionTrait
$elseBeforeStmtCount = count($this->context->beforeStmtLines);
$elseAfterStmtCount = count($this->context->afterStmtLines);
$else = $this->parseExpr($expr->else);
$else = $this->parseExprAsValue($expr->else);
$elseBeforeStmts = array_slice($this->context->beforeStmtLines, $elseBeforeStmtCount);
$elseAfterStmts = array_slice($this->context->afterStmtLines, $elseAfterStmtCount);
$this->context->beforeStmtLines = array_slice($this->context->beforeStmtLines, 0, $elseBeforeStmtCount);
@ -206,4 +206,3 @@ trait SelectionExpressionTrait
}
}

@ -0,0 +1,29 @@
--TEST--
concat assignment to an inherited property preserves value and reference arguments
--FILE--
<?php
class QueryConnection
{
protected $query = '';
}
class MongoConnection extends QueryConnection
{
public function build(): string
{
$this->query .= '.sort(' . json_encode(['id' => 1]) . ')';
$this->query .= '.skip(' . 2 . ')';
$this->query .= ';';
return $this->query;
}
}
function main(): void
{
$connection = new MongoConnection();
var_dump($connection->build());
}
?>
--EXPECT--
string(24) ".sort({"id":1}).skip(2);"

@ -0,0 +1,48 @@
--TEST--
ternary expressions convert void branches to null after their side effects
--FILE--
<?php
class OptimisticLock
{
private int $calls = 0;
public function check(bool $exists)
{
return $exists
? $this->updateLockVersion()
: $this->recordLockVersion();
}
public function calls(): int
{
return $this->calls;
}
private function updateLockVersion(): void
{
echo "update\n";
$this->calls++;
}
private function recordLockVersion(): void
{
echo "record\n";
$this->calls++;
}
}
function main(): void
{
$lock = new OptimisticLock();
var_dump($lock->check(true));
var_dump($lock->check(false));
var_dump($lock->calls());
}
?>
--EXPECT--
update
NULL
record
NULL
int(2)
Loading…
Cancel
Save