feat(parser): add readonly property unset protection

- Check for readonly property when calling unset on object properties
- Throw fatal error when attempting to unset readonly properties
- Add proper error message with property display name
- Include tests for unset operations on readonly properties
- Support both regular readonly properties and readonly class properties
- Ensure consistent error handling for readonly property access violations
pull/48/head
韩天峰 2 weeks ago
parent 3b51eaa6d0
commit a3ea91918d
  1. 16
      phpunit/code/unset-readonly-class-property.php
  2. 17
      phpunit/code/unset-readonly-property.php
  3. 13
      phpunit/src/UndefineTest.php
  4. 8
      src/Parser/PropertyAccessTrait.php

@ -0,0 +1,16 @@
<?php
readonly class ReadonlyClassPropertyUnset
{
public int $value;
public function __construct()
{
$this->value = 1;
}
public function clear(): void
{
unset($this->value);
}
}

@ -0,0 +1,17 @@
<?php
class ReadonlyPropertyUnset
{
public readonly int $value;
public function __construct()
{
$this->value = 1;
}
}
function main(): void
{
$object = new ReadonlyPropertyUnset();
unset($object->value);
}

@ -18,6 +18,19 @@ class UndefineTest extends \BaseTest
$this->exec('Attempt to unset static property', 'unset-static-prop.php');
}
public function testUnsetReadonlyPropertyIsRejected(): void
{
$this->exec('Cannot unset readonly property `ReadonlyPropertyUnset::$value`', 'unset-readonly-property.php');
}
public function testUnsetReadonlyClassPropertyIsRejected(): void
{
$this->exec(
'Cannot unset readonly property `ReadonlyClassPropertyUnset::$value`',
'unset-readonly-class-property.php'
);
}
public function testPropertyAccessOnUndefinedVar(): void
{
$this->compile('undefined-prop-access.php');

@ -737,6 +737,14 @@ trait PropertyAccessTrait
$propertyId = $this->getPropertyIdentifier($var, $var->var, $var->name);
$def = $this->getNativePropertyDef($var);
if ($def) {
if ($def->isReadonly()) {
$this->fatalError(
$var,
'Cannot unset readonly property `'
. $this->getObjectPropertyTypeCheckDisplayName($var)
. '`'
);
}
// Object typed properties are backed by Zend object
// properties, so PHP can represent their uninitialized
// state after unset(). Keep that behavior instead of

Loading…
Cancel
Save