- Add hooks property to PropertyInfo class with get/set method mappings - Register property hooks as Zend metadata during AOT compilation - Implement proper virtual property handling with ZEND_VIRTUAL_PROPERTY_OFFSET - Support object introspection via Reflection and iteration with hook invocation - Add reflection metadata exposure through ReflectionProperty::hasHooks() and getHooks() - Implement backing storage detection to distinguish virtual vs backed properties - Add comprehensive test coverage for property hooks introspection and reflection - Document lazy object limitation with persistent AOT class entries in PHP 8.4 - Update documentation to reflect property hooks compilation strategy changespull/48/head
parent
01ea7c40be
commit
2a1ca3b1a0
6 changed files with 167 additions and 6 deletions
@ -0,0 +1,51 @@ |
|||||||
|
--TEST-- |
||||||
|
PHP 8.4 object introspection invokes property get hooks |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
final class IntrospectedPropertyHooks |
||||||
|
{ |
||||||
|
private string $stored = 'initial'; |
||||||
|
|
||||||
|
public string $backed = 'raw' { |
||||||
|
get => strtoupper($this->backed); |
||||||
|
set (string $value) { |
||||||
|
$this->backed = trim($value); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public string $virtual { |
||||||
|
get => 'virtual:' . $this->stored; |
||||||
|
set (string $value) { |
||||||
|
$this->stored = $value; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$object = new IntrospectedPropertyHooks(); |
||||||
|
$object->backed = ' value '; |
||||||
|
$object->virtual = 'changed'; |
||||||
|
|
||||||
|
echo json_encode($object), "\n"; |
||||||
|
var_dump(get_object_vars($object)); |
||||||
|
foreach ($object as $name => $value) { |
||||||
|
echo $name, '=', $value, "\n"; |
||||||
|
} |
||||||
|
|
||||||
|
// PHP serialization exposes backing storage, not computed virtual values. |
||||||
|
echo serialize($object), "\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECTF-- |
||||||
|
{"backed":"VALUE","virtual":"virtual:changed"} |
||||||
|
array(2) { |
||||||
|
["backed"]=> |
||||||
|
string(5) "VALUE" |
||||||
|
["virtual"]=> |
||||||
|
string(15) "virtual:changed" |
||||||
|
} |
||||||
|
backed=VALUE |
||||||
|
virtual=virtual:changed |
||||||
|
O:25:"IntrospectedPropertyHooks":2:{s:33:"%0IntrospectedPropertyHooks%0stored";s:7:"changed";s:6:"backed";s:5:"value";} |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
--TEST-- |
||||||
|
PHP 8.4 property hooks expose Zend reflection metadata |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
final class ReflectedPropertyHooks |
||||||
|
{ |
||||||
|
public string $virtual { |
||||||
|
get => 'value'; |
||||||
|
set { |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$property = new ReflectionProperty(ReflectedPropertyHooks::class, 'virtual'); |
||||||
|
var_dump($property->hasHooks()); |
||||||
|
var_dump($property->isVirtual()); |
||||||
|
foreach ($property->getHooks() as $kind => $hook) { |
||||||
|
echo $kind, ':', $hook->getName(), ':', $hook->isFinal() ? 'final' : 'not-final', "\n"; |
||||||
|
} |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
bool(true) |
||||||
|
bool(true) |
||||||
|
get:$virtual::get:not-final |
||||||
|
set:$virtual::set:not-final |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
--TEST-- |
||||||
|
PHP 8.4 lazy objects reject persistent AOT class entries safely |
||||||
|
--SKIPIF-- |
||||||
|
<?php |
||||||
|
if (PHP_VERSION_ID < 80400) { |
||||||
|
die('skip requires PHP 8.4'); |
||||||
|
} |
||||||
|
?> |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
final class AotLazyObjectTarget |
||||||
|
{ |
||||||
|
public string $name; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$reflection = new ReflectionClass(AotLazyObjectTarget::class); |
||||||
|
try { |
||||||
|
$reflection->newLazyGhost(function (AotLazyObjectTarget $target): void { |
||||||
|
$target->name = 'loaded'; |
||||||
|
}); |
||||||
|
} catch (Error $error) { |
||||||
|
echo $error->getMessage(), "\n"; |
||||||
|
} |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
Cannot make instance of internal class lazy: AotLazyObjectTarget is internal |
||||||
Loading…
Reference in new issue