【问题标题】:spl_object_hash for PHP < 5.2 (unique ID for object instances)PHP < 5.2 的 spl_object_hash(对象实例的唯一 ID)
【发布时间】:2011-01-18 23:01:09
【问题描述】:

我正在尝试获取 PHP 5+ 中对象实例的唯一 ID。

函数 spl_object_hash() 可从 PHP 5.2 获得,但我想知道是否有针对旧 PHP 版本的解决方法。

php.net 上的 cmets 中有几个函数,但它们对我不起作用。第一个(简化):

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

不适用于原生对象(如 DOMDocument),第二个:

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

看起来它可能是一个主要的性能破坏者!

有没有人有事?

【问题讨论】:

  • 为什么需要这个?也许真正的解决方案是您不需要这个——这可能表明您的设计存在问题?
  • 我正在开发一个 CMS 并正在构建一个“事件”系统。可以使用以下代码触发事件:trigger('evt_name', new Event())。 CMS 插件可以使用bind('evt_name', 'callback_function')“绑定”到系统事件。我想做的是向两个函数添加另一个参数,该参数接受事件应该绑定到的实例,但是要存储事件数据(在对象本身之外),我需要将其转换为唯一的字符串以用作数组键。你有什么想法?
  • 我对此并没有真正的答案,但我虽然知道更多可能会有所帮助(即使不是我^^)——无论如何,我'从来没有觉得需要为一个对象获取任何类型的“唯一 ID”;;也许您只能在某处存储对该对象的引用?
  • 我可以存储对实例的引用,但这需要在每次触发事件时进行大量数组迭代(以检查每个绑定是否附加到触发事件的对象)。我知道还有其他方法可以解决这个问题,但我仍然想知道是否有更好的方法来模拟spl_object_hash()
  • 我也没有明确的答案,但它不是归结为一个简单的数组($obj,$data),其中的关键是无关紧要的吗?

标签: php spl


【解决方案1】:

我进行了几次快速测试。我真的认为您最好使用bind('evt_name', array($obj, 'callback_function')) 在您的bind() 函数中存储真正的回调。如果你绝对想走 spl_object_hash 路线,而不是使用事件绑定存储引用,你正在寻找这样的东西:

一个 var_dump / extract 和 hash 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-50 倍,所以不用担心。

按类实现的存储引用:

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 个类附近表现最好——在最好的情况下,它设法将基于 var_dump 的实现的性能提高了 1/3,而且通常要差得多 .

var_dump 的实现似乎是可以容忍的,但并不理想。但是,如果您没有进行太多此类查找,那么它不会成为您的瓶颈。特别是作为 PHP

【讨论】:

  • 哇,谢谢,我已经放弃了回答!我需要稍微消化一下您的代码(不过稍后,我正在工作;p),但我会尽快回复您。我正在编写的代码将是分布式系统的一部分,我希望支持 php5
【解决方案2】:

我曾经为 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 版本,则不需要通过引用传递参数。

【讨论】:

    【解决方案3】:

    这就是你想要的。

    我已经修复了一个非常可能的错误并将函数从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 了解您所看到的详细信息)。


    附:我在现实世界的场景中使用这个实现here

    【讨论】:

      【解决方案4】:

      uniqid() 会为您的任务工作吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-14
        • 2011-02-21
        • 2018-01-12
        • 2015-04-06
        • 1970-01-01
        • 2014-03-13
        • 2012-03-27
        相关资源
        最近更新 更多