Skip to content

Commit

Permalink
Deprecate IAP functions on objects
Browse files Browse the repository at this point in the history
Deprecate use of key(), current(), next(), prev(), reset() and
end() on objects. Cast the object to array first.

Part of https://wiki.php.net/rfc/deprecations_php_8_1.
  • Loading branch information
nikic committed Jul 8, 2021
1 parent 5bb83b3 commit dcc8463
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 13 deletions.
6 changes: 6 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,12 @@ PHP 8.1 UPGRADE NOTES
. The PDO::FETCH_SERIALIZE mode has been deprecated.
RFC: https://wiki.php.net/rfc/phase_out_serializable

- Standard:
. Calling key(), current(), next(), prev(), reset(), or end() on objects
is deprecated. Instead cast the object to array first, or make use of
ArrayIterator.
RFC: https://wiki.php.net/rfc/deprecations_php_8_1

========================================
5. Changed Functions
========================================
Expand Down
4 changes: 3 additions & 1 deletion Zend/tests/bug71266.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ $obj = (object) $arr;
next($obj);
var_dump(current($arr));
?>
--EXPECT--
--EXPECTF--
int(1)
int(42)

Deprecated: next(): Calling next() on an object is deprecated in %s on line %d
int(1)
32 changes: 32 additions & 0 deletions Zend/tests/iap_on_object_deprecated.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
Using IAP functions on objects is deprecated
--FILE--
<?php

$obj = (object)['a' => 'b'];
var_dump(reset($obj));
var_dump(current($obj));
var_dump(key($obj));
var_dump(next($obj));
var_dump(end($obj));
var_dump(prev($obj));

?>
--EXPECTF--
Deprecated: reset(): Calling reset() on an object is deprecated in %s on line %d
string(1) "b"

Deprecated: current(): Calling current() on an object is deprecated in %s on line %d
string(1) "b"

Deprecated: key(): Calling key() on an object is deprecated in %s on line %d
string(1) "a"

Deprecated: next(): Calling next() on an object is deprecated in %s on line %d
bool(false)

Deprecated: end(): Calling end() on an object is deprecated in %s on line %d
string(1) "b"

Deprecated: prev(): Calling prev() on an object is deprecated in %s on line %d
bool(false)
49 changes: 37 additions & 12 deletions ext/standard/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -1041,16 +1041,36 @@ PHP_FUNCTION(uksort)
}
/* }}} */

static inline HashTable *get_ht_for_iap(zval *zv, bool separate) {
if (EXPECTED(Z_TYPE_P(zv) == IS_ARRAY)) {
return Z_ARRVAL_P(zv);
}

ZEND_ASSERT(Z_TYPE_P(zv) == IS_OBJECT);
php_error_docref(NULL, E_DEPRECATED,
"Calling %s() on an object is deprecated", get_active_function_name());

zend_object *zobj = Z_OBJ_P(zv);
if (separate && zobj->properties && UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
GC_DELREF(zobj->properties);
}
zobj->properties = zend_array_dup(zobj->properties);
}
return zobj->handlers->get_properties(zobj);
}

/* {{{ Advances array argument's internal pointer to the last element and return it */
PHP_FUNCTION(end)
{
HashTable *array;
zval *array_zv;
zval *entry;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
Z_PARAM_ARRAY_OR_OBJECT_EX(array_zv, 0, 1)
ZEND_PARSE_PARAMETERS_END();

HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
zend_hash_internal_pointer_end(array);

if (USED_RET()) {
Expand All @@ -1070,13 +1090,14 @@ PHP_FUNCTION(end)
/* {{{ Move array argument's internal pointer to the previous element and return it */
PHP_FUNCTION(prev)
{
HashTable *array;
zval *array_zv;
zval *entry;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
Z_PARAM_ARRAY_OR_OBJECT_EX(array_zv, 0, 1)
ZEND_PARSE_PARAMETERS_END();

HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
zend_hash_move_backwards(array);

if (USED_RET()) {
Expand All @@ -1096,13 +1117,14 @@ PHP_FUNCTION(prev)
/* {{{ Move array argument's internal pointer to the next element and return it */
PHP_FUNCTION(next)
{
HashTable *array;
zval *array_zv;
zval *entry;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
Z_PARAM_ARRAY_OR_OBJECT_EX(array_zv, 0, 1)
ZEND_PARSE_PARAMETERS_END();

HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
zend_hash_move_forward(array);

if (USED_RET()) {
Expand All @@ -1122,13 +1144,14 @@ PHP_FUNCTION(next)
/* {{{ Set array argument's internal pointer to the first element and return it */
PHP_FUNCTION(reset)
{
HashTable *array;
zval *array_zv;
zval *entry;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
Z_PARAM_ARRAY_OR_OBJECT_EX(array_zv, 0, 1)
ZEND_PARSE_PARAMETERS_END();

HashTable *array = get_ht_for_iap(array_zv, /* separate */ true);
zend_hash_internal_pointer_reset(array);

if (USED_RET()) {
Expand All @@ -1148,13 +1171,14 @@ PHP_FUNCTION(reset)
/* {{{ Return the element currently pointed to by the internal array pointer */
PHP_FUNCTION(current)
{
HashTable *array;
zval *array_zv;
zval *entry;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_OR_OBJECT_HT(array)
Z_PARAM_ARRAY_OR_OBJECT(array_zv)
ZEND_PARSE_PARAMETERS_END();

HashTable *array = get_ht_for_iap(array_zv, /* separate */ false);
if ((entry = zend_hash_get_current_data(array)) == NULL) {
RETURN_FALSE;
}
Expand All @@ -1170,12 +1194,13 @@ PHP_FUNCTION(current)
/* {{{ Return the key of the element currently pointed to by the internal array pointer */
PHP_FUNCTION(key)
{
HashTable *array;
zval *array_zv;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY_OR_OBJECT_HT(array)
Z_PARAM_ARRAY_OR_OBJECT(array_zv)
ZEND_PARSE_PARAMETERS_END();

HashTable *array = get_ht_for_iap(array_zv, /* separate */ false);
zend_hash_get_current_key_zval(array, return_value);
}
/* }}} */
Expand Down

0 comments on commit dcc8463

Please sign in to comment.