1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

ext/spl: Deprecate SplObjectStorage::contains(), SplObjectStorage::attach(), and SplObjectStorage::detach() (#19424)

RFC: https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_splobjectstoragecontains_splobjectstorageattach_and_splobjectstoragedetach
This commit is contained in:
Gina Peter Banyard
2025-08-09 11:36:14 +01:00
committed by GitHub
parent 1e108e9ab2
commit 16872310d5
23 changed files with 80 additions and 46 deletions

View File

@@ -16,8 +16,8 @@ $storage[Foo::Baz] = 'Baz';
var_dump($storage[Foo::Bar]);
var_dump($storage[Foo::Baz]);
var_dump($storage->contains(Foo::Bar));
var_dump($storage->contains(Foo::Qux));
var_dump($storage->offsetExists(Foo::Bar));
var_dump($storage->offsetExists(Foo::Qux));
$serialized = serialize($storage);
var_dump($serialized);

View File

@@ -25,6 +25,7 @@
#include "zend_smart_str.h"
#include "zend_interfaces.h"
#include "zend_exceptions.h"
#include "zend_attributes.h"
#include "php_spl.h" /* For php_spl_object_hash() */
#include "spl_observer.h"

View File

@@ -23,12 +23,15 @@ interface SplSubject
class SplObjectStorage implements Countable, SeekableIterator, Serializable, ArrayAccess
{
/** @tentative-return-type */
#[\Deprecated(since: '8.5', message: "use method SplObjectStorage::offsetSet() instead")]
public function attach(object $object, mixed $info = null): void {}
/** @tentative-return-type */
#[\Deprecated(since: '8.5', message: "use method SplObjectStorage::offsetUnset() instead")]
public function detach(object $object): void {}
/** @tentative-return-type */
#[\Deprecated(since: '8.5', message: "use method SplObjectStorage::offsetExists() instead")]
public function contains(object $object): bool {}
/** @tentative-return-type */

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: a846c9dd240b6f0666cd5e805abfacabe360cf4c */
* Stub hash: 9dfd8bcf8946cbee550c9a46da07c424c3505408 */
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplObserver_update, 0, 1, IS_VOID, 0)
ZEND_ARG_OBJ_INFO(0, subject, SplSubject, 0)
@@ -185,9 +185,9 @@ static const zend_function_entry class_SplSubject_methods[] = {
};
static const zend_function_entry class_SplObjectStorage_methods[] = {
ZEND_ME(SplObjectStorage, attach, arginfo_class_SplObjectStorage_attach, ZEND_ACC_PUBLIC)
ZEND_ME(SplObjectStorage, detach, arginfo_class_SplObjectStorage_detach, ZEND_ACC_PUBLIC)
ZEND_ME(SplObjectStorage, contains, arginfo_class_SplObjectStorage_contains, ZEND_ACC_PUBLIC)
ZEND_ME(SplObjectStorage, attach, arginfo_class_SplObjectStorage_attach, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(SplObjectStorage, detach, arginfo_class_SplObjectStorage_detach, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(SplObjectStorage, contains, arginfo_class_SplObjectStorage_contains, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
ZEND_ME(SplObjectStorage, addAll, arginfo_class_SplObjectStorage_addAll, ZEND_ACC_PUBLIC)
ZEND_ME(SplObjectStorage, removeAll, arginfo_class_SplObjectStorage_removeAll, ZEND_ACC_PUBLIC)
ZEND_ME(SplObjectStorage, removeAllExcept, arginfo_class_SplObjectStorage_removeAllExcept, ZEND_ACC_PUBLIC)
@@ -258,6 +258,28 @@ static zend_class_entry *register_class_SplObjectStorage(zend_class_entry *class
class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0);
zend_class_implements(class_entry, 4, class_entry_Countable, class_entry_SeekableIterator, class_entry_Serializable, class_entry_ArrayAccess);
zend_attribute *attribute_Deprecated_func_attach_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "attach", sizeof("attach") - 1), ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2);
ZVAL_STR(&attribute_Deprecated_func_attach_0->args[0].value, ZSTR_KNOWN(ZEND_STR_8_DOT_5));
attribute_Deprecated_func_attach_0->args[0].name = ZSTR_KNOWN(ZEND_STR_SINCE);
zend_string *attribute_Deprecated_func_attach_0_arg1_str = zend_string_init("use method SplObjectStorage::offsetSet() instead", strlen("use method SplObjectStorage::offsetSet() instead"), 1);
ZVAL_STR(&attribute_Deprecated_func_attach_0->args[1].value, attribute_Deprecated_func_attach_0_arg1_str);
attribute_Deprecated_func_attach_0->args[1].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
zend_attribute *attribute_Deprecated_func_detach_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "detach", sizeof("detach") - 1), ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2);
ZVAL_STR(&attribute_Deprecated_func_detach_0->args[0].value, ZSTR_KNOWN(ZEND_STR_8_DOT_5));
attribute_Deprecated_func_detach_0->args[0].name = ZSTR_KNOWN(ZEND_STR_SINCE);
zend_string *attribute_Deprecated_func_detach_0_arg1_str = zend_string_init("use method SplObjectStorage::offsetUnset() instead", strlen("use method SplObjectStorage::offsetUnset() instead"), 1);
ZVAL_STR(&attribute_Deprecated_func_detach_0->args[1].value, attribute_Deprecated_func_detach_0_arg1_str);
attribute_Deprecated_func_detach_0->args[1].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
zend_attribute *attribute_Deprecated_func_contains_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "contains", sizeof("contains") - 1), ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2);
ZVAL_STR(&attribute_Deprecated_func_contains_0->args[0].value, ZSTR_KNOWN(ZEND_STR_8_DOT_5));
attribute_Deprecated_func_contains_0->args[0].name = ZSTR_KNOWN(ZEND_STR_SINCE);
zend_string *attribute_Deprecated_func_contains_0_arg1_str = zend_string_init("use method SplObjectStorage::offsetExists() instead", strlen("use method SplObjectStorage::offsetExists() instead"), 1);
ZVAL_STR(&attribute_Deprecated_func_contains_0->args[1].value, attribute_Deprecated_func_contains_0_arg1_str);
attribute_Deprecated_func_contains_0->args[1].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
return class_entry;
}

View File

@@ -19,15 +19,17 @@ var_dump(isset($s[$o2]));
var_dump(empty($s[$o2]));
$s[$o2] = null;
var_dump($s[$o2] ?? new stdClass());
echo "check isset/empty/contains for null. offsetExists returns true as long as the entry is there.\n";
echo "check isset/empty/contains/offsetExists for null. offsetExists returns true as long as the entry is there.\n";
var_dump(isset($s[$o2]));
var_dump(empty($s[$o2]));
var_dump($s->contains($o2));
echo "check isset/empty/contains for false.\n";
var_dump($s->offsetExists($o2));
echo "check isset/empty/contains/offsetExists for false.\n";
$s[$o2] = false;
var_dump(isset($s[$o2]));
var_dump(empty($s[$o2]));
var_dump($s->contains($o2));
var_dump($s->offsetExists($o2));
try {
$s['invalid'] = 123;
} catch (Error $e) {
@@ -56,18 +58,24 @@ bool(false)
bool(true)
object(stdClass)#4 (0) {
}
check isset/empty/contains for null. offsetExists returns true as long as the entry is there.
check isset/empty/contains/offsetExists for null. offsetExists returns true as long as the entry is there.
bool(true)
bool(true)
Deprecated: Method SplObjectStorage::contains() is deprecated since 8.5, use method SplObjectStorage::offsetExists() instead in %s on line %d
bool(true)
check isset/empty/contains for false.
bool(true)
check isset/empty/contains/offsetExists for false.
bool(true)
bool(true)
Deprecated: Method SplObjectStorage::contains() is deprecated since 8.5, use method SplObjectStorage::offsetExists() instead in %s on line %d
bool(true)
bool(true)
TypeError: SplObjectStorage::offsetSet(): Argument #1 ($object) must be of type object, string given
TypeError: SplObjectStorage::offsetExists(): Argument #1 ($object) must be of type object, string given
Notice: Indirect modification of overloaded element of SplObjectStorage has no effect in %s on line 38
Notice: Indirect modification of overloaded element of SplObjectStorage has no effect in %s on line %d
object(SplObjectStorage)#1 (1) {
["storage":"SplObjectStorage":private]=>
array(2) {

View File

@@ -10,16 +10,16 @@ $b = (object) 'b';
$c = (object) 'c';
$foo = new SplObjectStorage;
$foo->attach($a);
$foo->attach($b);
$foo->offsetSet($a);
$foo->offsetSet($b);
$bar = new SplObjectStorage;
$bar->attach($b);
$bar->attach($c);
$bar->offsetSet($b);
$bar->offsetSet($c);
$foo->removeAllExcept($bar);
var_dump($foo->contains($a));
var_dump($foo->contains($b));
var_dump($foo->offsetExists($a));
var_dump($foo->offsetExists($b));
?>
--EXPECT--

View File

@@ -64,8 +64,8 @@ var_dump($storage->current());
echo "--- With holes cases ---\n";
$storage->detach($b);
$storage->detach($d);
$storage->offsetUnset($b);
$storage->offsetUnset($d);
foreach (range(0, 2) as $index) {
$storage->seek($index);

View File

@@ -7,8 +7,8 @@ $o2 = new stdClass;
$s = new SplObjectStorage();
$s->attach($o1, array('prev' => 2, 'next' => $o2));
$s->attach($o2, array('prev' => $o1));
$s->offsetSet($o1, array('prev' => 2, 'next' => $o2));
$s->offsetSet($o2, array('prev' => $o1));
$ss = serialize($s);
unset($s,$o1,$o2);

View File

@@ -13,8 +13,8 @@ function LimitedScope()
$myB = new SplObjectStorage();
$myC = new myClass();
$myC->member = $myA; // myC has a reference to myA
$myB->Attach($myC); // myB attaches myC
$myA->member = $myB; // myA has myB, comleting the cycle
$myB->offsetSet($myC); // myB attaches myC
$myA->member = $myB; // myA has myB, completing the cycle
}
LimitedScope();
var_dump(gc_collect_cycles());

View File

@@ -11,7 +11,7 @@ class MyObjectStorage extends SplObjectStorage {
class TestObject {}
$list = new MyObjectStorage();
$list->attach(new TestObject());
$list->offsetSet(new TestObject());
foreach($list as $x) var_dump($list->offsetExists($x));

View File

@@ -9,7 +9,7 @@ $b = new SplObjectStorage();
for ($i = 10000; $i > 0; $i--) {
$object = new StdClass();
$a[] = $object;
$b->attach($object);
$b->offsetSet($object);
}
$c = serialize(array($a, $b));

View File

@@ -6,7 +6,7 @@ zend.enable_gc=1
<?php
$s = new SplObjectStorage();
$s->attach($s);
$s->offsetSet($s);
gc_collect_cycles();
echo "ok";
?>

View File

@@ -14,7 +14,7 @@ $b = new SplObjectStorage();
for ($i = 10000; $i > 0; $i--) {
$object = new StdClass();
$object->a = str_repeat("a", 2);
$b->attach($object);
$b->offsetSet($object);
}
?>
--EXPECTF--

View File

@@ -70,13 +70,13 @@ class SubjectImpl implements SplSubject
function attach(SplObserver $observer): void
{
echo $this->name . '->' . __METHOD__ . '(' . $observer->getName() . ");\n";
$this->observers->attach($observer);
$this->observers->offsetSet($observer);
}
function detach(SplObserver $observer): void
{
echo $this->name . '->' . __METHOD__ . '(' . $observer->getName() . ");\n";
$this->observers->detach($observer);
$this->observers->offsetUnset($observer);
}
function count(): int
@@ -100,7 +100,7 @@ class SubjectImpl implements SplSubject
function contains($obj)
{
return $this->observers->contains($obj);
return $this->observers->offsetExists($obj);
}
}

View File

@@ -17,7 +17,7 @@ $storage = new SplObjectStorage();
foreach(array(1,"2","foo",true) as $value)
{
$storage->attach(new TestClass($value));
$storage->offsetSet(new TestClass($value));
}
var_dump(count($storage));

View File

@@ -27,7 +27,7 @@ $storage = new MyStorage();
foreach(array(1,2) as $value)
{
$storage->attach(new TestClass($value));
$storage->offsetSet(new TestClass($value));
}
var_dump(count($storage));

View File

@@ -45,7 +45,7 @@ $storage = new MyStorage(1,2,3);
foreach(array(array(4,5,6),array(7,8,9)) as $value)
{
$storage->attach(new TestClass($value[0], $value[1], $value[2]));
$storage->offsetSet(new TestClass($value[0], $value[1], $value[2]));
}
var_dump(count($storage));

View File

@@ -27,7 +27,7 @@ $storage = new MyStorage();
foreach(array(1=>"foo",2=>42) as $key => $value)
{
$storage->attach(new TestClass($key), $value);
$storage->offsetSet(new TestClass($key), $value);
}
var_dump(count($storage));
@@ -52,8 +52,8 @@ foreach($storage2 as $object)
}
var_dump($storage2);
$storage->attach(new TestClass(3), new stdClass);
$storage->attach(new TestClass(4), new TestClass(5));
$storage->offsetSet(new TestClass(3), new stdClass);
$storage->offsetSet(new TestClass(4), new TestClass(5));
echo "===UNSERIALIZE2===\n";
var_dump(unserialize(serialize($storage)));
$storage->rewind();
@@ -70,7 +70,7 @@ $storage->next();
$storage->next();
var_dump($storage->key());
var_dump($storage->current());
$storage->attach($storage->current(), "replaced");
$storage->offsetSet($storage->current(), "replaced");
echo "===UNSERIALIZE4===\n";
var_dump(unserialize(serialize($storage)));

View File

@@ -9,24 +9,24 @@ $o2 = new StdClass;
$o3 = new StdClass;
$a = new A;
$a->attach($o1);
$a->attach($o2);
$a->offsetSet($o1);
$a->offsetSet($o2);
$b = new SplObjectStorage();
$b->attach($o2);
$b->attach($o3);
$b->offsetSet($o2);
$b->offsetSet($o3);
$a->addAll($b);
$a->offsetUnset($b);
var_dump($a->count());
$a->detach($o3);
$a->offsetUnset($o3);
var_dump($a->count());
$a->removeAll($b);
var_dump($a->count());
?>
--EXPECT--
int(3)
int(2)
int(2)
int(1)

View File

@@ -5,8 +5,8 @@ SPL: SplObjectStorage addAll/removeAll
class Foo {}
$storageA = new \SplObjectStorage();
$storageA->attach(new \Foo);
$storageA->attach(new \Foo);
$storageA->offsetSet(new \Foo);
$storageA->offsetSet(new \Foo);
echo ("Count storage A: " . count($storageA));
foreach ($storageA as $object) {