The SplObjectStorage class

(PHP 5 >= 5.3.0)

Introduction

The SplObjectStorage class provides a map from objects to data or, by ignoring data, an object set. This dual purpose can be useful in many cases involving the need to uniquely identify objects.

Class synopsis

SplObjectStorage implements Countable , Iterator , Serializable , ArrayAccess {
/* Methods */
public void addAll ( SplObjectStorage $storage )
public void attach ( object $object [, mixed $data = NULL ] )
public bool contains ( object $object )
public int count ( void )
public object current ( void )
public void detach ( object $object )
public string getHash ( object $object )
public mixed getInfo ( void )
public int key ( void )
public void next ( void )
public bool offsetExists ( object $object )
public mixed offsetGet ( object $object )
public void offsetSet ( object $object [, mixed $data = NULL ] )
public void offsetUnset ( object $object )
public void removeAll ( SplObjectStorage $storage )
public void removeAllExcept ( SplObjectStorage $storage )
public void rewind ( void )
public string serialize ( void )
public void setInfo ( mixed $data )
public void unserialize ( string $serialized )
public bool valid ( void )
}

Examples

Example #1 SplObjectStorage as a set

<?php
// As an object set
$s = new SplObjectStorage();

$o1 = new StdClass;
$o2 = new StdClass;
$o3 = new StdClass;

$s->attach($o1);
$s->attach($o2);

var_dump($s->contains($o1));
var_dump($s->contains($o2));
var_dump($s->contains($o3));

$s->detach($o2);

var_dump($s->contains($o1));
var_dump($s->contains($o2));
var_dump($s->contains($o3));
?>

The above example will output:

bool(true)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)

Example #2 SplObjectStorage as a map

<?php
// As a map from objects to data
$s = new SplObjectStorage();

$o1 = new StdClass;
$o2 = new StdClass;
$o3 = new StdClass;

$s[$o1] = "data for object 1";
$s[$o2] = array(1,2,3);

if (isset(
$s[$o2])) {
    
var_dump($s[$o2]);
}
?>

The above example will output:

array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

Table of Contents

Коментарии

Автор:
I rewrote some scripts and changed object storage with arrays to SplObjectStorage. At some point I needed support of array_rand() but I did not find a function to return a random attached object of an SplObjectStorage object.

So here is my solution for random access to SplObjectStorage:

<?php
$o1 
= new StdClass;
$o2 = new StdClass;
$s = new SplObjectStorage;
$s->attach($o1);
$s->attach($o2);

$random rand(0,$s->count()-1);
$s->rewind();
for(
$i=0;$i<$random;$i++) {
 
$s->next();
}
var_dump($s->current());
?>
2011-06-30 09:57:03
http://php5.kiev.ua/manual/ru/class.splobjectstorage.html
I needed to merge SplObjectStorages.
<?php
// As an object set
$SplObjectStorage_1 = new SplObjectStorage();

$object1 = new StdClass;
$object1->attr 'obj 1';
$object2 = new StdClass;
$object2->attr 'obj 2';
$object3 = new StdClass;
$object3->attr 'obj 3';

$SplObjectStorage_1->attach($object1);
$SplObjectStorage_1->attach($object2);
$SplObjectStorage_1->attach($object3);

// Another one object set
$SplObjectStorage_2 = new SplObjectStorage();

$object4 = new StdClass;
$object4->attr 'obj 4';
$object5 = new StdClass;
$object5->attr 'obj 5';
$object6 = new StdClass;
$object6->attr 'obj 6';

$SplObjectStorage_2->attach($object4);
$SplObjectStorage_2->attach($object5);
$SplObjectStorage_2->attach($object6);

/**
 * Merge SplObjectStorage
 *
 * @param how many SplObjectStorage params as you want
 * @return SplObjectStorage
 */
function mergeSplObjectStorage() {
   
   
$buffer   = new SplObjectStorage();

    if( 
func_num_args() > ) {
       
$args func_get_args();
        foreach (
$args as $objectStorage) {
            foreach(
$objectStorage as $object) {
                if(
is_object$object ) ) {
                   
$buffer->attach($object);
                }
            }
        }
    }
    else{
        return 
FALSE;
    }
    return 
$buffer;
}

$merge mergeSplObjectStorage($SplObjectStorage_1$SplObjectStorage_2);

?>
<?php
echo $merge->count();
?>
Will output :
6

<?php
$merge
->rewind();
while(
$merge->valid()) {
   
$object $merge->current();
   
var_dump($object);
   
$merge->next();
}
?>
Will ouput :
object(stdClass)#2 (1) {
  ["attr"]=>
  string(5) "obj 1"
}
object(stdClass)#3 (1) {
  ["attr"]=>
  string(5) "obj 2"
}
object(stdClass)#4 (1) {
  ["attr"]=>
  string(5) "obj 3"
}
object(stdClass)#6 (1) {
  ["attr"]=>
  string(5) "obj 4"
}
object(stdClass)#7 (1) {
  ["attr"]=>
  string(5) "obj 5"
}
object(stdClass)#8 (1) {
  ["attr"]=>
  string(5) "obj 6"
}

My two cents.
2012-02-29 01:01:00
http://php5.kiev.ua/manual/ru/class.splobjectstorage.html
Автор:
Note some inconsistent/surprising behavior in SplObjectStorage to preserve backwards compatibility. You can't properly use foreach with key/value syntax.

<?php
$spl 
= new SplObjectStorage ();
$keyForA = new StdClass();
$keyForB = new StdClass();
$spl[$keyForA] = 'value a';
$spl[$keyForB] = 'value b';
foreach (
$spl as $key => $value)
{
   
// $key is NOT an object, $value is!
    // Must use standard array access to get strings.
   
echo $spl[$value] . "\n"// prints "value a", then "value b"
}
// it may be clearer to use this form of foreach:
foreach ($spl as $key)
{
   
// $key is an object.
    // Use standard array access to get values.
   
echo $spl[$key] . "\n"// prints "value a", then "value b"
}
?>

See https://bugs.php.net/bug.php?id=49967
2014-01-07 19:48:21
http://php5.kiev.ua/manual/ru/class.splobjectstorage.html
Автор:
Do not use SplObjectStorage::detach when forach'ing over items in the storage as this skips the second (and only second) element.

Example:

<?php

class {
    public 
$i;
    public function 
__construct($i) {
       
$this->$i;
    }
}

$container = new \SplObjectStorage();

$container->attach(new A(1));
$container->attach(new A(2));
$container->attach(new A(3));
$container->attach(new A(4));
$container->attach(new A(5));

foreach (
$container as $item) {
    echo 
$item->"\n";
   
$container->detach($item);
}
echo 
"== Left in storage ==\n";
foreach (
$container as $item) {
    echo 
$item->"\n";
}
/* Outputs:
1
3
4
5
== Left in storage ==
2
*/
?>
2014-11-20 12:54:02
http://php5.kiev.ua/manual/ru/class.splobjectstorage.html
Please note that SplObjectStorage has a Bug introduced with 5.4.0, breaking object lookup in cloned instances of derived classes that overwrite getHash().

This is a confirmed Bug: https://bugs.php.net/bug.php?id=67582

Example:
<?php
class MyObjectStorage extends SplObjectStorage {
   
// Overwrite getHash() with just some (working) test-method
   
public function getHash($object) { return get_class($object); }
}

class 
TestObject {}

$list = new MyObjectStorage(); // No issues if using "new SplObjectStorage()"
$list->attach(new TestObject());

foreach(
$list as $xvar_dump($list->offsetExists($x)); // TRUE

$list2 = clone $list;
foreach(
$list2 as $xvar_dump($list2->offsetExists($x)); // FALSE
?>
2015-01-28 10:49:22
http://php5.kiev.ua/manual/ru/class.splobjectstorage.html
For anyone having issues with SplObjectStorages containing corrupt member variables after garbage collection (FatalErrorException after serializing): we used following fix to great effect
<?php

class FixedSplObjectStorage extends SplObjectStorage
{

    public function 
serialize()
    {
       
$goodPortion 'N;;m:a:0:{}';
       
$startKey 'N;;m:a:';

       
$serialized parent::serialize();

       
$startPos strpos($serialized$startKey);

        if (
$startPos !== false) {
           
$serialized substr_replace($serialized$goodPortion$startPos, -1);

        }

        return 
$serialized;

    }
}

?>
2015-05-22 10:41:46
http://php5.kiev.ua/manual/ru/class.splobjectstorage.html
Keep in mind that foreach() will copy your array before iterating, SplObjectStorage does not. If you have a sub call within an iteration that also calls foreach() on the object storage again, the iterator position collides!

To be safe use:
<?php
foreach(clone $myStorage as $obj) {

}
?>
2016-08-31 23:29:55
http://php5.kiev.ua/manual/ru/class.splobjectstorage.html
if you're looking for a ResourceStorage, check https://gist.github.com/divinity76/b8041e073b74bdeab562a075fc94217f

(i needed it for socket programming with socket_select())
2017-05-05 08:58:13
http://php5.kiev.ua/manual/ru/class.splobjectstorage.html
Автор:
<?php
/**
  * For simple use cases (where you want to keep objects in a map)
  * I would suggest to stick to an plain old array. Just use the object
  * hash as array key.
  */
$entity1 = new stdClass();
$entity2 = new stdClass();
$entities = [];
$entities[spl_object_hash($entity1)] = $entity1;
$entities[spl_object_hash($entity2)] = $entity2;

// object hashes are hard to distinguish so you could run a hash function
// on them for better readability.
$entities[md5(spl_object_hash($entity1))] = $entity1;
$entities[md5(spl_object_hash($entity2))] = $entity2;

print_r($entities);
2017-07-15 23:35:26
http://php5.kiev.ua/manual/ru/class.splobjectstorage.html
SplObjectStorage class can be nicely used in Observer pattern, for example:

<?php
class Subject implements \SplSubject
{
    private 
$observers;
   
    public function 
__construct()
    {
       
$this->observers = new \SplObjectStorage;
    }

    public function 
attach(\SplObserver $observer)
    {
       
$this->observers->attach($observer);
    }

    public function 
detach(\SplObserver $observer)
    {
       
$this->observers->detach($observer);
    }

    public function 
notify()
    {
        foreach (
$this->observers as $observer) {
           
$observer->update($this);
        }
    }
}
?>
2019-03-05 00:21:25
http://php5.kiev.ua/manual/ru/class.splobjectstorage.html
If you assign an array() to an object in SplObjectStorage and then try to modify its individual elements, you'll probably find it doesn't work.
Instead, you can use ArrayObject(), which will emulate array behaviour.

<?php

$storage 
= new SplObjectStorage();

$obj1 = new StdClass();
$obj2 = new StdClass();

$storage[$obj1] = array();
$storage[$obj2] = new ArrayObject();

$storage[$obj1]['person'] = 'Jana'// Won't work  (PHP Notice:  Indirect modification of overloaded element of SplObjectStorage has no effect)
$storage[$obj2]['person'] = 'Jana'// Works

var_dump($storage[$obj1]['person']); // NULL  (PHP Notice:  Undefined index: person)
var_dump($storage[$obj2]['person']); // string(4) "Jana"

?>
2021-05-20 21:32:55
http://php5.kiev.ua/manual/ru/class.splobjectstorage.html

    Поддержать сайт на родительском проекте КГБ