2010-02-19 58 views
5

我试图在PHP 5+中获取对象实例的唯一ID。用于PHP的spl_object_hash <5.2(对象实例的唯一ID)

函数spl_object_hash()可从PHP 5.2获得,但我想知道是否有一个解决方案适用于较老的PHP版本。

在php.net的评论中有几个函数,但他们不适合我。第(简体):

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

不与本地对象(如DOM文档),且第二工作:

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; 
    } 

看起来可能是一个重大的性能克星!

有没有人有他们的袖子?

+0

为什么你需要这个?也许真正的解决方案会让你不需要这个 - 这可能表明设计中存在一些问题? – 2010-02-19 20:55:33

+0

我正在研究CMS,并正在构建“事件”系统。事件可以使用以下代码触发:'trigger('evt_name',new Event())'。 CMS插件可以使用bind('evt_name','callback_function')'绑定'系统事件。我想要做的是为这两个函数添加另一个参数,该函数接受一个事件应该绑定的实例,但为了存储事件数据(在对象本身之外),我需要将它转换为一个唯一的字符串用作数组键。你怎么看? – Rowan 2010-02-19 21:02:00

+0

我对此没有真正的答案,但我知道更多可能会有所帮助*(即使不是我)^ - 不管怎样,我从来没有觉得有必要获得任何类型的“唯一ID“为一个对象;;也许你只能在某处存储对象的引用? – 2010-02-19 21:05:45

回答

4

我跑了几个快速测试。我真的认为你最好使用bind('evt_name', array($obj, 'callback_function'))在你的bind()函数中存储真正的回调。如果你绝对想要去的spl_object_hash路线,而不是存储与事件绑定的引用,你看是这样的:

一个的var_dump /提取和散列ID执行:

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; 
} 

一个天真的参考实现:

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; 
} 

这一次是比基本上整个蟒基于类的参考作用5-50x更糟rd,所以不值得担心。

一个引用存储由类实现:

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; 
} 

而且你结束了results that look like this。总结:基于类的引用实现执行最好的周围N/50类 - 在其最好的,它管理拉断1/3 var_dump根据实现的性能,而且它通常更糟。

var_dump实施似乎是可以容忍的,但效果并不理想。但是,如果你没有做太多这些查找,它不会成为你的瓶颈。特别是作为PHP < 5.2 boxen的后备。

+0

哇谢谢,我给了在获得答案!我需要消化你的代码(稍后,我正在工作; p),但我会尽快回复你。我正在编写的代码将成为分布式系统的一部分,我想支持php5 <5.2,但希望大部分时间5.2都可用。 – Rowan 2010-03-17 10:38:08

0

请问uniqid()是否适合您的任务?

1

我曾经写过一个辅助函数为WordPress,提供了每个对象一个唯一的哈希,它与计数器和存储哈希每一个公共类属性,如果它已经被分配给一个对象。下面的例子说明了这一点:

/** 
* get object hash 
* 
* Returns a unique hash per object. 
* 
* Proxy function for wordpress installments on servers 
* with a PHP version < 5.2.0. 
* 
* @since 3.0.2 
* @note Become deprecated with version 3.2.0 (PHP 5.2 requirements) 
* @param object $object 
* @return string unique object hash 
*/ 
function wp_object_hash(&$object) { 
    static $prefix, $count = 0, $property = '__wphookobjhash__', $spl_function_exists; 

    isset($spl_function_exists) || $spl_function_exists = function_exists('spl_object_hash'); 

    // prefer spl_object_hash if available 
    if ($spl_function_exists) 
     return spl_object_hash($object); 

    // validate input 
    if (!is_object($object)) { 
     trigger_error(__FUNCTION__ . '() expects parameter 1 to be object', E_USER_WARNING); 
     return null; 
    } 
    // setup prefix and counter to generate object hash, set it to object if not set 
    isset($prefix) || (($prefix = uniqid('')) && $property .= $prefix . '__'); 
    isset($object->$property) || ($object->$property = sprintf('%s-%08d', $prefix , ++$count)); 
    return $object->$property; 
} 

如果您使用的是PHP 5的版本,则不需要通过引用传递参数。

1

这是你想要的。

我已经修复了一个非常可能的错误和精简从bobthecow answer此函数(其也从php.net借):

if (!function_exists('spl_object_hash')) { 
    function spl_object_hash($object) 
    { 
     ob_start(); 
     var_dump($object); 
     preg_match('[#(\d+)]', ob_get_clean(), $match); 
     return $match[1]; 
    } 
} 

它返回一个整数(通常在亚100范围),这对于任何对象都是唯一的(有关您所看到的内容的详细信息,请参阅this answer)。


P.S.我在真实世界场景中使用此实现here