spl_object_hash для PHP < 5.2 (уникальный идентификатор для экземпляров объекта)

Я пытаюсь получить уникальные идентификаторы для экземпляров объектов в PHP 5+.

Функция, spl_object_hash() доступно из PHP 5.2, но мне интересно, есть ли обходной путь для старых версий PHP.

В комментариях на php.net есть несколько функций, но они не работают для меня. Первое (упрощенное):

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

Похоже, что это может быть основной производительности!

У кого-нибудь есть что-нибудь в рукаве?

4 ответа

Решение

Я провел пару быстрых тестов. Я действительно думаю, что вам лучше хранить реальные обратные вызовы в вашей функции bind(), используя bind('evt_name', array($obj, 'callback_function')), Если вы абсолютно хотите идти по пути 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;
}

И вы получите результаты, которые выглядят так. Резюме: реализация ссылок на основе классов лучше всего работает с n/50 классами - в лучшем случае ей удается добиться 1/3 производительности var_dump основанная реализация, и это обычно намного хуже.

var_dump реализация кажется терпимой, хотя и не идеальной. Но если вы не будете выполнять слишком много таких поисков, это не станет для вас узким местом. Особенно как запасной вариант для PHP < 5.2 boxen.

Это то, что вы хотите.

Я исправил очень вероятную ошибку и оптимизировал функцию из ответа bobthecow (который также заимствован из 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), уникальное для любого объекта (подробности о том, что вы видите, смотрите в этом ответе).


PS Я использую эту реализацию в реальном сценарии здесь

Однажды я написал вспомогательную функцию для wordpress, которая предлагает один уникальный хэш для каждого объекта, он работает со счетчиком и сохраняет хэш per в качестве свойства открытого класса, если он был назначен объекту. Следующий пример демонстрирует это:

/**
 * 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, вам не нужно передавать параметр по ссылке.

Будет ли uniqid() работать для вашей задачи?

Другие вопросы по тегам