PHP Conference Japan 2024

SplObjectStorage::detach

(PHP 5 >= 5.1.0, PHP 7, PHP 8)

SplObjectStorage::detach从存储中移除一个 对象

描述

public SplObjectStorage::detach(对象 $object): void

从存储中移除 对象

参数

object

要移除的 对象

返回值

不返回任何值。

示例

示例 #1 SplObjectStorage::detach() 示例

<?php
$o
= new stdClass;
$s = new SplObjectStorage();
$s->attach($o);
var_dump(count($s));
$s->detach($o);
var_dump(count($s));
?>

以上示例将输出类似以下内容

int(1)
int(0)

参见

添加注释

用户贡献的注释 4 条注释

r dot wilczek at web-appz dot de
14 年前
从存储中分离当前条目会阻止 SplObjectStorage::next() 操作。

作为 PHPUnit 测试的示例

<?php
public function testDetachingCurrentPreventsNext()
{
$storage = new SplObjectStorage;
$storage->attach(new stdClass);
$storage->attach(new stdClass);
$storage->rewind();
$iterated = 0;
$expected = $storage->count();
while (
$storage->valid()) {
$iterated++;
$storage->detach($storage->current());
$storage->next();
}
$this->assertEquals($expected, $iterated);
}
?>

此测试将失败,因为迭代将永远无法到达第二个 stdClass。
SplObjectStorage::next() 显然依赖于当前元素有效。

如果要在迭代期间分离对象,则应在调用 next() 之前取消引用对象,并在 next() 之后分离引用

<?php
public function testDetachingReferenceAfterNext()
{
$storage = new SplObjectStorage;
$storage->attach(new stdClass);
$storage->attach(new stdClass);
$storage->rewind();
$iterated = 0;
$expected = $storage->count();
while (
$storage->valid()) {
$iterated++;
$object = $storage->current();
$storage->next();
$storage->detach($object);
}
$this->assertEquals($expected, $iterated);
}
?>

此测试将通过。
alan dot bem at gmail dot com
11 年前
SplObjectSotage::detach() 有一个 bug - 它会重绕内部数组指针。
记住这一点 - 当循环遍历存储时 - 因为它没有解决方法。

https://bugs.php.net/bug.php?id=65629&edit=2
nawa
1 年前
在循环内部分离对象时存在问题的情况,因为 SplObjectStorage 需要在 detach() 之前调用 next()

使用 foreach 的示例
<?php
/**
* 使用 SplObjectStorage 循环时的 Bug
* @see https://bugs.php.net/bug.php?id=65629
*/
$firstStorage = new SplObjectStorage();
$secondStorage = new SplObjectStorage();
// 临时存储
$temporaryStorage = new SplObjectStorage();
// 范围 0 - 9
$range = range(0, 9);

foreach (
$range as $id) {
$object = new stdClass();
$object->id = $id;
$firstStorage->attach($object);
$secondStorage->attach($object);
}

// 在循环内部直接分离
foreach ($firstStorage as $storage) {
// 在普通数组中,即使在循环中,它也会分离所有元素
// 但对象存储仍然保留 1 个对象
if ($storage->id < 5) {
$firstStorage->detach($storage);
}
}

// 将存储收集到临时 SplObjectStorage 中
foreach ($secondStorage as $storage) {
// 收集到临时存储中
if ($storage->id < 5) {
$temporaryStorage->attach($storage);
}
}
// 通过临时存储移除所有元素
$secondStorage->removeAll($temporaryStorage);

var_dump(count($firstStorage)); // int(6)
var_dump(count($secondStorage)); // int(5)
?>

使用 while 循环的示例
<?php
$firstStorage
= new SplObjectStorage();
$secondStorage = new SplObjectStorage();
// 临时存储
$temporaryStorage = new SplObjectStorage();
// 范围 0 - 9
$range = range(0, 9);

foreach (
$range as $id) {
$object = new stdClass();
$object->id = $id;
$firstStorage->attach($object);
$secondStorage->attach($object);
}

$firstStorage->rewind();
while (
$firstStorage->valid() && ($current = $firstStorage->current())) {
if (
$current->id < 5) {
$firstStorage->detach($current);
}
// 在分离后不要调用 next
$firstStorage->next();
}

$secondStorage->rewind();
while (
$secondStorage->valid() && ($current = $secondStorage->current())) {
// 在分离前调用 next 的行为
$secondStorage->next();
if (
$current->id < 5) {
$secondStorage->detach($current);
}
}

var_dump(count($firstStorage)); // int(6)
var_dump(count($secondStorage)); // int(5)
?>
Hayley Watson
6 年前
如果您尝试分离集合中不存在的对象,SplObjectStorage 不会报错;它将不执行任何操作。

<?php

$o
= new StdClass;
$t = new StdClass;
$s = new SplObjectStorage();
$s->attach($o);
var_dump(count($s));
$s->detach($t); // 未附加此对象。
var_dump(count($s));

?>
To Top