2010-02-19 3 views
5

Ich versuche, eindeutige IDs für Objektinstanzen in PHP 5+ zu bekommen.spl_object_hash für PHP <5.2 (eindeutige ID für Objektinstanzen)

Die Funktion, spl_object_hash() ist von PHP 5.2 verfügbar, aber ich frage mich, ob es eine Problemumgehung für ältere PHP-Versionen gibt.

Es gibt ein paar Funktionen in den Kommentaren auf php.net, aber sie funktionieren nicht für mich. Die erste (vereinfacht):

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

nicht mit nativen Objekten funktioniert (wie DOMDocument) und die zweite:

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

sieht aus wie es eine große Leistung buster sein könnte!

Hat jemand etwas im Ärmel?

+0

Warum brauchen Sie das? Vielleicht ist die wirkliche Lösung, dass Sie das nicht brauchen - was auf ein Problem in Ihrem Design hindeuten könnte? –

+0

Ich arbeite an einem CMS und baue ein 'Event' System. Ereignisse können mit folgendem Code ausgelöst werden: 'trigger ('evt_name', new Event())'. CMS-Plugins können mit 'bind ('evt_name', 'callback_function')' an Systemereignisse 'binden'. Was ich tun möchte, ist ein weiteres Argument für beide Funktionen hinzuzufügen, das eine Instanz akzeptiert, an die ein Ereignis gebunden werden soll. Um Ereignisdaten (außerhalb des Objekts selbst) zu speichern, muss ich sie jedoch in eine eindeutige Zeichenfolge konvertieren Array-Schlüssel. Was sind deine Gedanken? – Rowan

+0

Ich habe keine Antwort darauf, aber wenn ich mehr weiß, könnte es vielleicht helfen * (auch wenn nicht ich ^^) * - Egal was, ich habe noch nie das Bedürfnis verspürt irgendeine Art von " eindeutige ID "für ein Objekt ;; Vielleicht könntest du nur einen Verweis auf das Objekt speichern? –

Antwort

4

Ich habe ein paar schnelle Tests durchgeführt. Ich denke wirklich, dass es besser wäre, echte Callbacks in Ihrer bind() - Funktion zu speichern, indem Sie bind('evt_name', array($obj, 'callback_function')) verwenden. Wenn Sie unbedingt die spl_object_hash Weg gehen wollen, anstatt Referenzen mit den Ereignisbindungen zu speichern, sind Sie auf der Suche auf etwas wie folgt aus:

A Var_dump/Extrakt und Hash-ID Implementierung:

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

eine naive Referenzen Umsetzung:

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

Dieser war im Grunde 5-50x schlechter als die klassenbasierte Referenzfunktion für die boa rd, also lohnt es sich nicht, sich Sorgen zu machen.

Ein Geschäft Referenzen von Klassenimplementierung:

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

und Sie am Ende mit results that look like this auf. Zusammenfassung: Die klassenbasierte Referenzimplementierung schneidet am besten bei n/50 Klassen ab - im besten Fall erreicht sie 1/3 der Performance der var_dump basierten Implementierung, und es ist normalerweise viel schlechter.

Die var_dump Implementierung scheint zu tolerieren, obwohl nicht ideal. Aber wenn Sie nicht zu viele dieser Nachschlagewerke machen, ist das kein Flaschenhals für Sie. Besonders als Ausweichmöglichkeit für PHP < 5.2 Boxen.

+0

wow danke, hätte ich gegeben eine Antwort bekommen! Ich muss deinen Code ein wenig verdauen (später bin ich bei der Arbeit; p), aber ich melde mich wieder bei dir. Der Code, den ich schreibe, wird Teil eines verteilten Systems sein, und ich würde gerne php5 <5.2 unterstützen, aber hoffentlich wird die meiste Zeit 5.2 verfügbar sein. – Rowan

0

Würde uniqid() für Ihre Aufgabe arbeiten?

1

Ich schrieb einmal eine Hilfsfunktion für WordPress, die einen eindeutigen Hash pro Objekt bietet, sie arbeitet mit einem Zähler und speichert den Hash pro als öffentliche Klasseneigenschaft, wenn sie einem Objekt zugewiesen wurde. Das folgende Beispiel zeigt dies:

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

Wenn Sie eine PHP-5-Version verwenden, können Sie den Parameter nicht als Verweis übergeben müssen.

1

Das ist, was Sie wollen.

ich einen sehr wahrscheinlichen Fehler und rationalisierte die Funktion von bobthecow answer behoben habe, um diese (die auch von php.net entlehnt ist):

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

Es gibt eine ganze Zahl (in der Regel in den Sub-100 Bereich), die für jedes Objekt einzigartig ist (siehe this answer für Details zu dem, was Sie sehen).


P.S. Ich verwende diese Implementierung in einem realen Szenario here