Ankündigung

Einklappen
Keine Ankündigung bisher.

Eigenschaften von Objekten vergleichen

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Eigenschaften von Objekten vergleichen

    Hallo, ich möchte Objekte vergleichen und dabei feststellen, ob die öffentlichen Eigenschaften identisch sind.
    Für den Import von Daten möchte ich vorher prüfen, ob ein solcher Datensatz bereits vorliegt, auch wenn es keinen eindeutigen Primärschlüssel gibt, der eine Identifikation möglich machen würde.

    So habe ich eine erste Idee einer Methode geschrieben und nach einigen Tests zeigt sich, dass das passiert, was ich erwarte.

    PHP-Code:
        public static function hashObject($obj$ignore null)
        {
            
    $clone = clone $obj;
            if (
    is_array($ignore))
            {
                foreach ((array)
    $ignore as $key)
                {
                    if (isset(
    $clone->{$key}))
                    {
                        unset(
    $clone->{$key});
                    }
                }
            }
            return 
    md5(serialize($clone));        
        } 
    In der Anwendung:
    Während des ersten "Durchlaufes" speichere ich jeweils die Daten in der Datenbank und erzeuge über die oben gezeigte Methode einen Hash, denn ich auch in der Datenbank für jeden Datensatz speichere. Während des Durchlaufes und bei späteren Importen wende ich die Methode auf alle zu speichernden Objekte an und prüfe, ob ein solches "Objekt" schon existiert. Während des Vorgangs entferne ich ggf. Daten aus dem Objekt, die sich ggf. ändern könnten, aber keine Interpretation als "neu" zulassen sollen.

    Meine Fragen nun dazu: Übersehe ich etwas? Gibt es noch einen einfacheren Weg, zwei Objekte in dieser Art zu vergleichen?
    Wie eindeutig ist ein so erzeugter Hash bei einem Datenvolumen von ca. 100.000 Datensätzen?
    Lässt sich das Ganze optimieren?

    Viele Grüße
    ec

  • #2
    So ein hash ist wahrscheinlich so eindeutig, dass die Wahrscheinlichkeit einer Kollision äußerst gering ist. Drauf verlassen würde ich mich aber nicht unbedingt. Hashes sind nicht dafür da, eine Identität eines Inputs zu stellen.

    Kommentar


    • #3
      Könntest du das Objekt nicht zu einem array casten und dann einfach vergleichen? Macht das ganze ein bisschen transparenter finde ich.

      Das ignore könntest du dir evtl. auch sparen wenn du auf http://php.net/manual/de/language.oo...p#object.clone setzt.

      Kommentar


      • #4
        PHP-Code:

        interface iMyComparable {
            public function 
        equal($obj);
        }

        class 
        implements iMyComparable {
            public 
        $a;
            public 
        $b;
            public 
        $c;
            
            public function 
        __construct($a$b$c) {
                
        $this->$a;
                
        $this->$b;
                
        $this->$c;
            }
            
            public function 
        equal($obj) {
                
        $vars get_object_vars($obj);
                
        $_vars get_object_vars($this);
                
                if (
        count($vars) != count($_vars))
                    return 
        false;
                
                foreach(
        $vars as $name => $value) {
                    if (!isset(
        $_vars[$name]) || $value !== $_vars[$name])
                        return 
        false;
                }
                return 
        true;
            }
        }
        class 
        {
            public 
        $a;
            public 
        $b;
            
            public function 
        __construct($a$b) {
                
        $this->$a;
                
        $this->$b;
            }
        }
        class 
        {
            public 
        $a;
            public 
        $b;
            public 
        $d;
            
            public function 
        __construct($a$b$d) {
                
        $this->$a;
                
        $this->$b;
                
        $this->$d;
            }
        }


        $a = new A(1,3,4);

        $a2 = new A(1,3,5);
        var_dump$a->equal($a2) ); // false

        $a3 = new A(1,3,4);
        var_dump$a->equal($a3) ); // true

        $b = new B(1,3);
        var_dump$a->equal($b) ); // false

        $c = new C(1,3,4);
        var_dump$a->equal($c) ); // false 
        edit: Oh, merke grad da ist noch ein Fehler drin.. sekunde

        edit2: fixed
        Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.

        Kommentar


        • #5
          Auf jeden Fall. Ich schreibe ab jetzt allen meinen Objekten vor, dass die ein "equal" implementieren sollen. Tolle Idee
          Ja, Sarkasmus...

          Kommentar


          • #6
            Ich würde die ReflectionClass hernehmen, per getProperties(ReflectionMethod::IS_PUBLIC)) mir alle public Properties beider Instanzen holen, und diese dann direkt vergleichen.

            Nachtrag:
            serialize() erfasst nicht nur die öffentlichen Eigenschaften, sondern alle (public, protected + private)!

            Und obige Methode (#1) lässt nur Vergleiche zu, deren Instanzen vom selben Object stammen
            PHP-Code:
             class a{}

            $a = new a;
            $a->7;

            $b = new a;
            $b->7;

            $hash_a hashObject($a);
            $hash_b hashObject($b);
            //sind gleich 
            Dagegen:
            PHP-Code:
            class a{}
            class 
            b{}

            $a = new a;
            $a->7;

            $b = new b;  //hier jetzt b
            $b->7;

            $hash_a hashObject($a);
            $hash_b hashObject($b);
            //sind ungleich 
            Ein Vergleich nur über die public properties beider Objekte würde für den 2.Fall auch ein gleich ergeben.
            Ist halt die frage, was genau gebraucht wird.

            Nachtrag 2:

            Mit einem Beispiel vor Augen, wo zwei unterschiedliche Strings den gleichen md5 liefern, ist man nicht mehr sicher ob md5 eine gute Methode ist Strings auf Gleichheit zu prüfen.
            PHP-Code:
            <?php
            $s1 
            "M\xc9h\xff\x0e\xe3\ \x95r\xd4w{r\x15\x87\xd3o\xa7\xb2\x1b\xdcV\xb7J=\xc0x>{\x95\x18\xaf\xbf\xa2\x00\xa8(K\xf3n\x8eKU\xb3_Bu\x93\xd8Igm\xa0\xd1U]\x83`\xfb_\x07\xfe\xa2";
            $s2 "M\xc9h\xff\x0e\xe3\ \x95r\xd4w{r\x15\x87\xd3o\xa7\xb2\x1b\xdcV\xb7J=\xc0x>{\x95\x18\xaf\xbf\xa2\x02\xa8(K\xf3n\x8eKU\xb3_Bu\x93\xd8Igm\xa0\xd1\xd5]\x83`\xfb_\x07\xfe\xa2";
            var_dump($s1==$s2md5($s1)==md5($s2)); //bool(false) bool(true)
            online: eval.in

            LG jspit

            Kommentar


            • #7
              Zitat von jspit Beitrag anzeigen
              Ich würde die ReflectionClass hernehmen, per getProperties(ReflectionMethod::IS_PUBLIC)) mir alle public Properties beider Instanzen holen, und diese dann direkt vergleichen.
              oder gleich "get_object_vars()" benutzen

              get_object_varsLiefert die öffentlichen Elemente eines Objekts
              @rkr: Es ging mir eigentlich nur um "get_object_vars" - die Implementationsdetails sind Wumpe.
              Hier als globale Funktion für zwei Objekte.

              PHP-Code:
              function equals($obj1$obj2) {
                  
              $vars get_object_vars($obj1);
                  
              $_vars get_object_vars($obj2);
                  
                  if (
              count($vars) != count($_vars))
                      return 
              false;
                  
                  foreach(
              $vars as $name => $value) {
                      if (!isset(
              $_vars[$name]) || $value !== $_vars[$name])
                          return 
              false;
                  }
                  return 
              true;

              Dieser Funktion ist egal, ob die Klassen unterschiedlich sind, sie vergleicht ganz stumpf die public members.

              Zitat von jspit Beitrag anzeigen
              Ist halt die frage, was genau gebraucht wird.
              Ganz genau!
              Über 90% aller Gewaltverbrechen passieren innerhalb von 24 Stunden nach dem Konsum von Brot.

              Kommentar


              • #8
                Zitat von lstegelitz Beitrag anzeigen

                oder gleich "get_object_vars()" benutzen
                Jo, ist einfacher. Je nachdem wie es gebraucht wird, kann auch
                PHP-Code:
                if( get_object_vars($obj1) == get_object_vars($obj2){ //gleich


                ausreichen.

                Werden dann die Arrays mit json_encode in ein String konvertiert, hab ich gegenüber md5 eine sichere Vergleichsmöglichkeit, die ich auch in der DB ablegen kann.
                Macht jedoch nur Sinn, wenn die Arrays vom Umfang nicht zu groß werden.

                LG + ein schönes Wochenende
                jspit

                Kommentar


                • #9
                  Hallo,
                  leider komme ich erst jetzt wieder dazu reinzusehen. Vielen Dank für die tolle Diskussion und die vielen Anregungen. Damit kann ich sehr viel anfangen.

                  Vermutlich werde ich am Ende tatsächlich zwei Arrays vergleichen.

                  Manchmal sieht man den Wald vor lauter Bäumen nicht.
                  Viele Grüße
                  ec

                  Kommentar

                  Lädt...
                  X