Problem
PHPCfg parses Expr_AssignOp_* (e.g. $s .= $x, $n += 1), but lib/Compiler.php::compileExpr() has no lowering — lint reports Expr_AssignOp_ via #136 in UnsupportedRegistry.php.
Templates and counters use .= constantly; for loops (#192) often use += / ++ (#137).
Goal
All common compound assigns used in small web apps: at minimum .=, +=, -=, *=, /=, .=.
Implementation hints
Compiler (lib/Compiler.php)
- In
compileExpr(), handle Op\Expr\AssignOp\Concat, Plus, Minus, etc. (grep AssignOp under vendor/ircmaxell/php-cfg for exact class names).
- Lower to read-modify-write: load target → apply binary op → store (may emit two
TYPE_ASSIGN sequences before a dedicated opcode exists).
VM
lib/Runtime.php already wires Optimizer\AssignOp — check if VM opcodes can delegate or mirror that resolver.
lib/VM.php: ensure string .= uses string concat, numeric += uses numeric add (no silent cast surprises vs Zend).
JIT (lib/JIT.php)
- String
.=: LLVM call to existing string concat builtin path (same as . binary op).
- Numeric compound ops: reuse arithmetic LLVM helpers from
lib/JIT/Builtin/.
Tests
test/compliance/cases/assignop_concat.phpt: $x = 'a'; $x .= 'b'; echo $x;
test/compliance/cases/assignop_plus.phpt: $n = 1; $n += 2; echo $n;
- Register in capability matrix when JIT parity lands.
Acceptance criteria
docker run --rm -v "$(pwd):/compiler" -w /compiler php-compiler:22.04-dev \
php bin/vm.php -r '\$s = "Hello"; \$s .= " World"; echo \$s;'
docker run --rm -v "$(pwd):/compiler" -w /compiler php-compiler:22.04-dev \
php bin/jit.php -r '\$s = "Hello"; \$s .= " World"; echo \$s;'
Both print Hello World. phpc lint clean for scripts using only supported assign ops.
Dependencies
Verification (local / Docker only)
./script/ci-local.sh --filter assignop — no GitHub Actions required.
Links
Problem
PHPCfgparsesExpr_AssignOp_*(e.g.$s .= $x,$n += 1), butlib/Compiler.php::compileExpr()has no lowering — lint reportsExpr_AssignOp_via #136 inUnsupportedRegistry.php.Templates and counters use
.=constantly;forloops (#192) often use+=/++(#137).Goal
All common compound assigns used in small web apps: at minimum
.=,+=,-=,*=,/=,.=.Implementation hints
Compiler (
lib/Compiler.php)compileExpr(), handleOp\Expr\AssignOp\Concat,Plus,Minus, etc. (grepAssignOpundervendor/ircmaxell/php-cfgfor exact class names).TYPE_ASSIGNsequences before a dedicated opcode exists).VM
lib/Runtime.phpalready wiresOptimizer\AssignOp— check if VM opcodes can delegate or mirror that resolver.lib/VM.php: ensure string.=uses string concat, numeric+=uses numeric add (no silent cast surprises vs Zend).JIT (
lib/JIT.php).=: LLVM call to existing string concat builtin path (same as.binary op).lib/JIT/Builtin/.Tests
test/compliance/cases/assignop_concat.phpt:$x = 'a'; $x .= 'b'; echo $x;test/compliance/cases/assignop_plus.phpt:$n = 1; $n += 2; echo $n;Acceptance criteria
Both print
Hello World.phpc lintclean for scripts using only supported assign ops.Dependencies
??, Language: Ternary operator (?:) in compiler pipeline #114?:, Language: Double-quoted string interpolation ($var, {$obj->x}) #261 string interpolation (template building)Verification (local / Docker only)
./script/ci-local.sh --filter assignop— no GitHub Actions required.Links
lib/VM/Optimizer/AssignOp.php,lib/Lint/UnsupportedRegistry.php