views:

192

answers:

2

I'm trying to get unique IDs for object instances in PHP 5+.

The function, spl_object_hash() is available from PHP 5.2 but I'm wondering if there's a workaround for older versions.

There are a couple of functions in the comments on php.net but they're not working for me. The first (simplified):

function spl_object_hash($object){
    if (is_object($object)){
        return md5((string)$object);
        }
    return null;
    }

does not work with native objects (such as DOMDocument), and the second:

function spl_object_hash($object){
    if (is_object($object)){
        ob_start();
        var_dump($object);
        $dump = ob_get_contents();
        ob_end_clean();
        if (preg_match('/^object\(([a-z0-9_]+)\)\#(\d)+/i', $dump, $match)) {
            return md5($match[1] . $match[2]);
            }
        }
    return null;
    }

looks like it could be a major performance buster!

Does anybody have anything up their sleeve?

A: 

Would uniqid() work for your task?

z-boss
+1  A: 

I ran a couple of quick tests. I really think you'd be better off storing real callbacks in your bind() function using bind('evt_name', array($obj, 'callback_function')). If you absolutely want to go the spl_object_hash route, rather than storing references with the event bindings, you're looking at something like this:

A var_dump / extract and hash id implementation:

function spl_object_hash_var_dump($object){
    if (is_object($object)){
        ob_start();
        var_dump($object);
        $dump = ob_get_contents();
        ob_end_clean();
        if (preg_match('/^object\(([a-z0-9_]+)\)\#(\d)+/i', $dump, $match)) {
            return md5($match[1] . $match[2]);
            }
        }
    return null;
}

A naive references implementation:

function spl_object_dumb_references(&$object) {
    static $hashes;

    if (!isset($hashes)) $hashes = array();

    // find existing instance
    foreach ($hashes as $hash => $o) {
        if ($object === $o) return $hash;
    }

    $hash = md5(uniqid());
    while (array_key_exists($hash, $hashes)) {
        $hash = md5(uniqid());
    }

    $hashes[$hash] = $object;
    return $hash;
}

This one was basically 5-50x worse than the class-based reference function across the board, so it's not worth worrying about.

A store references by class implementation:

function spl_object_hash_references(&$object) {
    static $hashes;

    if (!isset($hashes)) $hashes = array();

    $class_name = get_class($object);
    if (!array_key_exists($class_name, $hashes)) {
        $hashes[$class_name] = array();
    }

    // find existing instance
    foreach ($hashes[$class_name] as $hash => $o) {
        if ($object === $o) return $hash;
    }

    $hash = md5(uniqid($class_name));
    while (array_key_exists($hash, $hashes[$class_name])) {
        $hash = md5(uniqid($class_name));
    }

    $hashes[$class_name][$hash] = $object;
    return $hash;
}

And you end up with results that look like this. Summary: the class based references implementation performs best around n/50 classes--at its best, it manages to pull off 1/3 the performance of the var_dump based implementation, and it's usually much worse.

The var_dump implementation seems to be tolerable, though not ideal. But if you're not doing too many of these lookups, it won't be a bottleneck for you. Especially as a fallback for PHP < 5.2 boxen.

bobthecow
wow thanks, I'd given up on getting an answer! I need to digest your code a bit (later though, I'm at work ;p) but I'll get back to you. The code I'm writing will be part of a distributed system, and I'd like to support php5<5.2 but hopefully most of the time 5.2 will be available.
Rowan