3

I was reading around about the Observer pattern, and found a dated article. Having read through, I noticed an interesting mention in this paragraph:

The key methods to look at here are attach(), detach(), and notify(). attach() and detach() handle adding and removing observers. We use a little trick here. Objects quoted in string context resolve to a unique identifier (even if __toString() is defined). You can use this fact to build keys for an associative array. The notify() method cycles through all attached observers, calling update() on each. The UploadManager class calls notify() whenever it has something important to report on upload and on error, in this case.

Which references this example:

function attach(UploadObserver $obs) {
    $this->observers["$obs"] = $obs;
}

Now as mentioned, this article is dated. Casting objects to strings of course no longer works in this manner (I run 5.3.6 on my dev box, and push it for all client projects) but I'd like to achieve similar functionality. I can only think of (something like) this:

function attach(Observer $observer){
    $this->_observers[md5(serialize($observer))] = $observer;
}

function detach(Observer $observer){
    unset($this->_observers[md5(serialize($observer))]);
}

I'm curious, are there any other efficient ways to achieve this; creating a unique key from the object itself.

Caveat: I don't want to get into defined keys, I use those often enough with other repositories and such, implementing __set($key, $value), etc.

Note: I understand MD5 isn't ideal.


Update: Just found spl_object_hash, and I assume this is likely my best choice, however feel free to share your thoughts.

Dan Lugg
  • 20,192
  • 19
  • 110
  • 174
  • you have just found or mario have just told you it? :P – dynamic Jun 15 '11 at 15:44
  • `spl_object_hash` is conceptually broken (returns same hashes for different objects), but you normally do not run into a problem by that when in use. – hakre Jun 15 '11 at 15:45
  • @yes123: Found it and was editing. Saved edits, and answers appeared. – Dan Lugg Jun 15 '11 at 15:47
  • @hakre: it returns same hashes or not? – dynamic Jun 15 '11 at 15:48
  • Interesting note: According to http://www.php.net/manual/en/function.spl-object-hash.php#76220 (*given internals haven't changed*) it hashes the internal handle. When an identical object is created immediately after the first has been destroyed, it can produce identical hashes. – Dan Lugg Jun 15 '11 at 15:53
  • @TomcatExodus: That's the case I was referring to. But that should not be an issue in your code. – hakre Jun 15 '11 at 16:10

3 Answers3

1

Have you tried the SPL object hash function?

Robin
  • 4,242
  • 1
  • 20
  • 20
1

You're right that does not work that way any longer. You might want to use some other function instead: spl_object_hash()

function attach(Observer $observer){
    $this->_observers[spl_object_hash($observer)] = $observer;
}

function detach(Observer $observer){
    unset($this->_observers[spl_object_hash($observer)]);
}

The serialization based approach has a design problem btw: I stops working when objects are identical by value or in other words if objects return the same serialized value, e.g. NULL. This is fully controllable by the objects themselves when they implement the Serializable interface.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • Thanks **hakre**; Found `spl_object_hash` and was editing as you answered :) Also, yes I'm aware of the Spl interfaces; The mention of the Observer pattern was more of a vessel to my actual question, regarding the object IDs. Thanks for the mention of the serialization issue, hadn't occurred to me. – Dan Lugg Jun 15 '11 at 15:45
1

Alternatively you could use SplObjectStorage directly.

Like:

function __construct(...){
    $this->_observers = new SplObjectStorage;
}

function attach(Observer $observer) {
    $this->_observers[$observer] = $observer;
}

function detach(Observer $observer){
    unset($this->_observers[$observer]);
}
Yoshi
  • 54,081
  • 14
  • 89
  • 103