PHP Conference Japan 2024

SplObjectStorage::detach

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

SplObjectStorage::detach從儲存空間移除一個物件

說明

公開 SplObjectStorage::detach(物件 $object):

從儲存區移除指定物件。

參數

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() 有一個錯誤 - 它會重設內部陣列指標。
請記住 - 當循環遍歷儲存時 - 因為它沒有解決方法。

https://bugs.php.net/bug.php?id=65629&edit=2
nawa
1 年前
在迴圈內分離物件時會出現問題,因為 SplObjectStorage 需要在 detach() 之前呼叫 next()

使用 foreach 的範例
<?php
/**
* spl 物件儲存迴圈時的錯誤
* @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);
}

// 直接在迴圈內 detach
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);
}
// detach 後不要呼叫 next
$firstStorage->next();
}

$secondStorage->rewind();
while (
$secondStorage->valid() && ($current = $secondStorage->current())) {
// 在 detach 之前呼叫 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 年前
如果您嘗試 detach 一個不在集合中的物件,SplObjectStorage 不會產生任何錯誤訊息;它只是一個無效操作 (no-op)。

<?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