mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Merge branch 'PHP-8.2'
* PHP-8.2: By-ref modification of typed and readonly props through ArrayIterator
This commit is contained in:
commit
a86796e52a
4 changed files with 128 additions and 5 deletions
26
Zend/tests/type_declarations/typed_properties_113.phpt
Normal file
26
Zend/tests/type_declarations/typed_properties_113.phpt
Normal file
|
@ -0,0 +1,26 @@
|
|||
--TEST--
|
||||
Typed property type coercion through ArrayIterator
|
||||
--FILE--
|
||||
<?php
|
||||
class A implements IteratorAggregate {
|
||||
function __construct(
|
||||
public string $foo = 'bar'
|
||||
) {}
|
||||
|
||||
function getIterator(): Traversable {
|
||||
return new ArrayIterator($this);
|
||||
}
|
||||
}
|
||||
|
||||
$obj = new A;
|
||||
foreach ($obj as $k => &$v) {
|
||||
$v = 42;
|
||||
}
|
||||
|
||||
var_dump($obj);
|
||||
?>
|
||||
--EXPECT--
|
||||
object(A)#1 (1) {
|
||||
["foo"]=>
|
||||
&string(2) "42"
|
||||
}
|
39
Zend/tests/type_declarations/typed_properties_114.phpt
Normal file
39
Zend/tests/type_declarations/typed_properties_114.phpt
Normal file
|
@ -0,0 +1,39 @@
|
|||
--TEST--
|
||||
Typed property type error through ArrayIterator
|
||||
--FILE--
|
||||
<?php
|
||||
class A implements IteratorAggregate {
|
||||
function __construct(
|
||||
public string $foo = 'bar'
|
||||
) {}
|
||||
|
||||
function getIterator(): Traversable {
|
||||
return new ArrayIterator($this);
|
||||
}
|
||||
}
|
||||
|
||||
$obj = new A;
|
||||
foreach ($obj as $k => &$v) {
|
||||
try {
|
||||
$v = [];
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
}
|
||||
foreach ($obj as $k => &$v) {
|
||||
try {
|
||||
$v = [];
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
}
|
||||
|
||||
var_dump($obj);
|
||||
?>
|
||||
--EXPECT--
|
||||
Cannot assign array to reference held by property A::$foo of type string
|
||||
Cannot assign array to reference held by property A::$foo of type string
|
||||
object(A)#1 (1) {
|
||||
["foo"]=>
|
||||
&string(3) "bar"
|
||||
}
|
30
Zend/tests/type_declarations/typed_properties_115.phpt
Normal file
30
Zend/tests/type_declarations/typed_properties_115.phpt
Normal file
|
@ -0,0 +1,30 @@
|
|||
--TEST--
|
||||
Readonly property modification error through ArrayIterator
|
||||
--FILE--
|
||||
<?php
|
||||
class A implements IteratorAggregate {
|
||||
function __construct(
|
||||
public readonly string $foo = 'bar'
|
||||
) {}
|
||||
|
||||
function getIterator(): Traversable {
|
||||
return new ArrayIterator($this);
|
||||
}
|
||||
}
|
||||
|
||||
$obj = new A;
|
||||
|
||||
try {
|
||||
foreach ($obj as $k => &$v) {}
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
var_dump($obj);
|
||||
?>
|
||||
--EXPECT--
|
||||
Cannot acquire reference to readonly property A::$foo
|
||||
object(A)#1 (1) {
|
||||
["foo"]=>
|
||||
string(3) "bar"
|
||||
}
|
|
@ -56,6 +56,11 @@ typedef struct _spl_array_object {
|
|||
zend_object std;
|
||||
} spl_array_object;
|
||||
|
||||
typedef struct _spl_array_iterator {
|
||||
zend_object_iterator it;
|
||||
bool by_ref;
|
||||
} spl_array_iterator;
|
||||
|
||||
static inline spl_array_object *spl_array_from_obj(zend_object *obj) /* {{{ */ {
|
||||
return (spl_array_object*)((char*)(obj) - XtOffsetOf(spl_array_object, std));
|
||||
}
|
||||
|
@ -978,12 +983,34 @@ static int spl_array_it_valid(zend_object_iterator *iter) /* {{{ */
|
|||
|
||||
static zval *spl_array_it_get_current_data(zend_object_iterator *iter) /* {{{ */
|
||||
{
|
||||
spl_array_iterator *array_iter = (spl_array_iterator*)iter;
|
||||
spl_array_object *object = Z_SPLARRAY_P(&iter->data);
|
||||
HashTable *aht = spl_array_get_hash_table(object);
|
||||
zval *data = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, object));
|
||||
if (data && Z_TYPE_P(data) == IS_INDIRECT) {
|
||||
data = Z_INDIRECT_P(data);
|
||||
}
|
||||
// ZEND_FE_FETCH_RW converts the value to a reference but doesn't know the source is a property.
|
||||
// Typed properties must add a type source to the reference, and readonly properties must fail.
|
||||
if (array_iter->by_ref
|
||||
&& Z_TYPE_P(data) != IS_REFERENCE
|
||||
&& Z_TYPE(object->array) == IS_OBJECT
|
||||
&& !(object->ar_flags & (SPL_ARRAY_IS_SELF|SPL_ARRAY_USE_OTHER))) {
|
||||
zend_string *key;
|
||||
zend_hash_get_current_key_ex(aht, &key, NULL, spl_array_get_pos_ptr(aht, object));
|
||||
zend_class_entry *ce = Z_OBJCE(object->array);
|
||||
zend_property_info *prop_info = zend_get_property_info(ce, key, true);
|
||||
if (ZEND_TYPE_IS_SET(prop_info->type)) {
|
||||
if (prop_info->flags & ZEND_ACC_READONLY) {
|
||||
zend_throw_error(NULL,
|
||||
"Cannot acquire reference to readonly property %s::$%s",
|
||||
ZSTR_VAL(prop_info->ce->name), ZSTR_VAL(key));
|
||||
return NULL;
|
||||
}
|
||||
ZVAL_NEW_REF(data, data);
|
||||
ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), prop_info);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -1103,13 +1130,14 @@ static const zend_object_iterator_funcs spl_array_it_funcs = {
|
|||
|
||||
static zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
|
||||
{
|
||||
zend_object_iterator *iterator = emalloc(sizeof(zend_object_iterator));
|
||||
zend_iterator_init(iterator);
|
||||
spl_array_iterator *iterator = emalloc(sizeof(spl_array_iterator));
|
||||
zend_iterator_init(&iterator->it);
|
||||
|
||||
ZVAL_OBJ_COPY(&iterator->data, Z_OBJ_P(object));
|
||||
iterator->funcs = &spl_array_it_funcs;
|
||||
ZVAL_OBJ_COPY(&iterator->it.data, Z_OBJ_P(object));
|
||||
iterator->it.funcs = &spl_array_it_funcs;
|
||||
iterator->by_ref = by_ref;
|
||||
|
||||
return iterator;
|
||||
return &iterator->it;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue