Category
Language · php-src-strict · asymmetric visibility · pillar 4
Problem
When a subclass method assigns to an inherited private(set) property, Zend throws Error: Cannot modify private(set) property A::$x from scope B with Error::getLine() = the assignment line inside the method. VM reports the call site line instead.
Message text matches; only the attributed source line (and thus stack top) diverges.
Probed 2026-08-10 vs php:8.4-cli with PHP_COMPILER_PROFILE=8.4.
| Repro |
Zend 8.4 getLine() |
VM getLine() |
B::setX does $this->x = $v; then $b->setX('z') |
line of $this->x = $v (inside setX) |
line of $b->setX('z') (caller) |
php-src reference
PHP implementation target
lib/VM/ / lib/JIT/ property write path for private(set) / protected(set) — throw with the assign opcode location (method body), not the call opcode
- No new C runtime
Repro
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
cat > /tmp/private_set_line.php << "PHP"
<?php
class A { public private(set) string $x = "a"; }
class B extends A {
public function setX(string $v): void { $this->x = $v; }
}
$b = new B();
try { $b->setX("z"); } catch (Error \$e) {
echo \$e->getMessage(), "\nline=", \$e->getLine(), "\n";
}
PHP
PHP_COMPILER_PROFILE=8.4 php bin/vm.php /tmp/private_set_line.php
# Zend: line=4 (assignment). VM today: line=7 (call).
'
Done when
Category
Language· php-src-strict · asymmetric visibility · pillar 4Problem
When a subclass method assigns to an inherited
private(set)property, Zend throwsError: Cannot modify private(set) property A::$x from scope BwithError::getLine()= the assignment line inside the method. VM reports the call site line instead.Message text matches; only the attributed source line (and thus stack top) diverges.
Probed 2026-08-10 vs
php:8.4-cliwithPHP_COMPILER_PROFILE=8.4.getLine()getLine()B::setXdoes$this->x = $v;then$b->setX('z')$this->x = $v(insidesetX)$b->setX('z')(caller)php-src reference
Zend/zend_object_handlers.c— asymmetric visibility /private(set)write checksZend/zend_execute.c— property assign opcodesPHP implementation target
lib/VM//lib/JIT/property write path forprivate(set)/protected(set)— throw with the assign opcode location (method body), not the call opcodeRepro
Done when
Error::getLine()for forbiddenprivate(set)write matches Zend (assignment in method), VM+JIT$b->x = …from outside still errors with correct external line.phptundertest/compliance/cases/