diff --git a/Zend/tests/property_hooks/unserialize.phpt b/Zend/tests/property_hooks/unserialize.phpt index 2461817a08814..b8834e1d39ff4 100644 --- a/Zend/tests/property_hooks/unserialize.phpt +++ b/Zend/tests/property_hooks/unserialize.phpt @@ -54,7 +54,7 @@ object(Test)#2 (1) { Test::$prop3::get Test::$prop3::set -Warning: unserialize(): Cannot unserialize value for hooked property Test::$prop3 in %s on line %d +Warning: unserialize(): Cannot unserialize value for virtual property Test::$prop3 in %s on line %d Warning: unserialize(): Error at offset 26 of 32 bytes in %s on line %d bool(false) diff --git a/build/gen_stub.php b/build/gen_stub.php index 1d92ddd46b9ee..bbdd8a85f145f 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -2916,6 +2916,7 @@ class PropertyInfo extends VariableLike public ?Expr $defaultValue; public ?string $defaultValueString; public bool $isDocReadonly; + public bool $isVirtual; /** * @var AttributeInfo[] $attributes @@ -2929,6 +2930,7 @@ public function __construct( ?Expr $defaultValue, ?string $defaultValueString, bool $isDocReadonly, + bool $isVirtual, ?string $link, ?int $phpVersionIdMinimumCompatibility, array $attributes, @@ -2939,6 +2941,7 @@ public function __construct( $this->defaultValue = $defaultValue; $this->defaultValueString = $defaultValueString; $this->isDocReadonly = $isDocReadonly; + $this->isVirtual = $isVirtual; parent::__construct($flags, $type, $phpDocType, $link, $phpVersionIdMinimumCompatibility, $attributes, $exposedDocComment); } @@ -3054,6 +3057,10 @@ protected function getFlagsByPhpVersion(): array $flags = $this->addFlagForVersionsAbove($flags, "ZEND_ACC_READONLY", PHP_82_VERSION_ID); } + if ($this->isVirtual) { + $flags = $this->addFlagForVersionsAbove($flags, "ZEND_ACC_VIRTUAL", PHP_84_VERSION_ID); + } + return $flags; } @@ -4433,6 +4440,7 @@ function parseProperty( ): PropertyInfo { $phpDocType = null; $isDocReadonly = false; + $isVirtual = false; $link = null; if ($comments) { @@ -4444,6 +4452,8 @@ function parseProperty( $isDocReadonly = true; } elseif ($tag->name === 'link') { $link = $tag->value; + } elseif ($tag->name === 'virtual') { + $isVirtual = true; } } } @@ -4472,6 +4482,7 @@ function parseProperty( $property->default, $property->default ? $prettyPrinter->prettyPrintExpr($property->default) : null, $isDocReadonly, + $isVirtual, $link, $phpVersionIdMinimumCompatibility, $attributes, diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 0956bbc1acf70..1d26c80f222bf 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6041,7 +6041,7 @@ ZEND_METHOD(ReflectionProperty, getSettableType) } /* Get-only virtual property can never be written to. */ - if ((prop->flags & ZEND_ACC_VIRTUAL) && !prop->hooks[ZEND_PROPERTY_HOOK_SET]) { + if (prop->hooks && (prop->flags & ZEND_ACC_VIRTUAL) && !prop->hooks[ZEND_PROPERTY_HOOK_SET]) { zend_type never_type = ZEND_TYPE_INIT_CODE(IS_NEVER, 0, 0); reflection_type_factory(never_type, return_value, 0); return; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 78d102eefda6c..cbd457e16fdb1 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -561,7 +561,7 @@ static int is_property_visibility_changed(zend_class_entry *ce, zval *key) return 1; } else { php_error_docref(NULL, E_WARNING, - "Cannot unserialize value for hooked property %s::$%s", + "Cannot unserialize value for virtual property %s::$%s", ZSTR_VAL(existing_propinfo->ce->name), Z_STRVAL_P(key)); zval_ptr_dtor_str(key); return -1; diff --git a/ext/xmlreader/php_xmlreader.stub.php b/ext/xmlreader/php_xmlreader.stub.php index c58ee2460ff02..d319037066046 100644 --- a/ext/xmlreader/php_xmlreader.stub.php +++ b/ext/xmlreader/php_xmlreader.stub.php @@ -99,32 +99,46 @@ class XMLReader public const int SUBST_ENTITIES = UNKNOWN; + /** @virtual */ public int $attributeCount; + /** @virtual */ public string $baseURI; + /** @virtual */ public int $depth; + /** @virtual */ public bool $hasAttributes; + /** @virtual */ public bool $hasValue; + /** @virtual */ public bool $isDefault; + /** @virtual */ public bool $isEmptyElement; + /** @virtual */ public string $localName; + /** @virtual */ public string $name; + /** @virtual */ public string $namespaceURI; + /** @virtual */ public int $nodeType; + /** @virtual */ public string $prefix; + /** @virtual */ public string $value; + /** @virtual */ public string $xmlLang; /** @tentative-return-type */ diff --git a/ext/xmlreader/php_xmlreader_arginfo.h b/ext/xmlreader/php_xmlreader_arginfo.h index a5a0c12cd2593..d4ee1c9d8f1c9 100644 --- a/ext/xmlreader/php_xmlreader_arginfo.h +++ b/ext/xmlreader/php_xmlreader_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 551324d130f9755c4c61cebb5084953fb6f539c4 */ + * Stub hash: 80288a0f40eabc7802a928963386616ea31e448d */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_XMLReader_close, 0, 0, IS_TRUE, 0) ZEND_END_ARG_INFO() @@ -313,85 +313,85 @@ static zend_class_entry *register_class_XMLReader(void) zval property_attributeCount_default_value; ZVAL_UNDEF(&property_attributeCount_default_value); zend_string *property_attributeCount_name = zend_string_init("attributeCount", sizeof("attributeCount") - 1, 1); - zend_declare_typed_property(class_entry, property_attributeCount_name, &property_attributeCount_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_declare_typed_property(class_entry, property_attributeCount_name, &property_attributeCount_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_attributeCount_name); zval property_baseURI_default_value; ZVAL_UNDEF(&property_baseURI_default_value); zend_string *property_baseURI_name = zend_string_init("baseURI", sizeof("baseURI") - 1, 1); - zend_declare_typed_property(class_entry, property_baseURI_name, &property_baseURI_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_declare_typed_property(class_entry, property_baseURI_name, &property_baseURI_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release(property_baseURI_name); zval property_depth_default_value; ZVAL_UNDEF(&property_depth_default_value); zend_string *property_depth_name = zend_string_init("depth", sizeof("depth") - 1, 1); - zend_declare_typed_property(class_entry, property_depth_name, &property_depth_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_declare_typed_property(class_entry, property_depth_name, &property_depth_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_depth_name); zval property_hasAttributes_default_value; ZVAL_UNDEF(&property_hasAttributes_default_value); zend_string *property_hasAttributes_name = zend_string_init("hasAttributes", sizeof("hasAttributes") - 1, 1); - zend_declare_typed_property(class_entry, property_hasAttributes_name, &property_hasAttributes_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_declare_typed_property(class_entry, property_hasAttributes_name, &property_hasAttributes_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); zend_string_release(property_hasAttributes_name); zval property_hasValue_default_value; ZVAL_UNDEF(&property_hasValue_default_value); zend_string *property_hasValue_name = zend_string_init("hasValue", sizeof("hasValue") - 1, 1); - zend_declare_typed_property(class_entry, property_hasValue_name, &property_hasValue_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_declare_typed_property(class_entry, property_hasValue_name, &property_hasValue_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); zend_string_release(property_hasValue_name); zval property_isDefault_default_value; ZVAL_UNDEF(&property_isDefault_default_value); zend_string *property_isDefault_name = zend_string_init("isDefault", sizeof("isDefault") - 1, 1); - zend_declare_typed_property(class_entry, property_isDefault_name, &property_isDefault_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_declare_typed_property(class_entry, property_isDefault_name, &property_isDefault_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); zend_string_release(property_isDefault_name); zval property_isEmptyElement_default_value; ZVAL_UNDEF(&property_isEmptyElement_default_value); zend_string *property_isEmptyElement_name = zend_string_init("isEmptyElement", sizeof("isEmptyElement") - 1, 1); - zend_declare_typed_property(class_entry, property_isEmptyElement_name, &property_isEmptyElement_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_declare_typed_property(class_entry, property_isEmptyElement_name, &property_isEmptyElement_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); zend_string_release(property_isEmptyElement_name); zval property_localName_default_value; ZVAL_UNDEF(&property_localName_default_value); zend_string *property_localName_name = zend_string_init("localName", sizeof("localName") - 1, 1); - zend_declare_typed_property(class_entry, property_localName_name, &property_localName_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_declare_typed_property(class_entry, property_localName_name, &property_localName_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release(property_localName_name); zval property_name_default_value; ZVAL_UNDEF(&property_name_default_value); zend_string *property_name_name = zend_string_init("name", sizeof("name") - 1, 1); - zend_declare_typed_property(class_entry, property_name_name, &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_declare_typed_property(class_entry, property_name_name, &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release(property_name_name); zval property_namespaceURI_default_value; ZVAL_UNDEF(&property_namespaceURI_default_value); zend_string *property_namespaceURI_name = zend_string_init("namespaceURI", sizeof("namespaceURI") - 1, 1); - zend_declare_typed_property(class_entry, property_namespaceURI_name, &property_namespaceURI_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_declare_typed_property(class_entry, property_namespaceURI_name, &property_namespaceURI_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release(property_namespaceURI_name); zval property_nodeType_default_value; ZVAL_UNDEF(&property_nodeType_default_value); zend_string *property_nodeType_name = zend_string_init("nodeType", sizeof("nodeType") - 1, 1); - zend_declare_typed_property(class_entry, property_nodeType_name, &property_nodeType_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_declare_typed_property(class_entry, property_nodeType_name, &property_nodeType_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(property_nodeType_name); zval property_prefix_default_value; ZVAL_UNDEF(&property_prefix_default_value); zend_string *property_prefix_name = zend_string_init("prefix", sizeof("prefix") - 1, 1); - zend_declare_typed_property(class_entry, property_prefix_name, &property_prefix_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_declare_typed_property(class_entry, property_prefix_name, &property_prefix_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release(property_prefix_name); zval property_value_default_value; ZVAL_UNDEF(&property_value_default_value); zend_string *property_value_name = zend_string_init("value", sizeof("value") - 1, 1); - zend_declare_typed_property(class_entry, property_value_name, &property_value_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_declare_typed_property(class_entry, property_value_name, &property_value_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release(property_value_name); zval property_xmlLang_default_value; ZVAL_UNDEF(&property_xmlLang_default_value); zend_string *property_xmlLang_name = zend_string_init("xmlLang", sizeof("xmlLang") - 1, 1); - zend_declare_typed_property(class_entry, property_xmlLang_name, &property_xmlLang_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + zend_declare_typed_property(class_entry, property_xmlLang_name, &property_xmlLang_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_VIRTUAL, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release(property_xmlLang_name); return class_entry; diff --git a/ext/xmlreader/tests/virtual_properties.phpt b/ext/xmlreader/tests/virtual_properties.phpt new file mode 100644 index 0000000000000..57499292b8ce0 --- /dev/null +++ b/ext/xmlreader/tests/virtual_properties.phpt @@ -0,0 +1,34 @@ +--TEST-- +Virtual property tests +--EXTENSIONS-- +xmlreader +--FILE-- +getProperty("nodeType"); +var_dump($prop->isVirtual()); +var_dump($prop->getSettableType()); +var_dump($prop->getHooks()); +var_dump($prop->getRawValue(new XMLReader)); +var_dump($prop->getValue(new XMLReader)); + +$reader = XMLReader::XML("hi"); +var_dump(json_encode($reader)); +var_export($reader); echo "\n"; +var_dump(get_object_vars($reader)); + +?> +--EXPECTF-- +bool(true) +object(ReflectionNamedType)#%d (0) { +} +array(0) { +} +int(0) +int(0) +string(2) "{}" +\XMLReader::__set_state(array( +)) +array(0) { +}