Ankündigung

Einklappen
Keine Ankündigung bisher.

[Erledigt] Komisches Verhalten von $this bei Vererbung

Einklappen

Neue Werbung 2019

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

  • [Erledigt] Komisches Verhalten von $this bei Vererbung

    Hallo,

    Ich bin bisher davon ausgegangen, dass $this in Methoden immer eine Referenz auf das aufrufende Objekt ist. Also bei einem Aufruf der Form „objekt->methode()“ sollte ein in der Definition von „methode“ vorkommendes $this jetzt auf „objekt“ zeigen.

    Bei folgendem Beispiel ist das aber nicht so:



    PHP-Code:
    class {

            private 
    $x 'a';

            public function 
    test() {

                    echo 
    $this->x;

            }

    }


    class 
    extends {

            private 
    $x 'b';

    }


    $b = new B();

    $b->test();        // Ausgabe: 'a'! 


    Ich erwarte als Ausgabe 'b', weil ja die Methode test von $b aufgerufen wurde und das $this entsprechend auf das Attribut B::$x mit dem Wert 'b' zeigen sollte. Aber stattdessen wird das nicht-statische Attribut $x der Basisklasse irgendwie statisch (?) aufgerufen.

    Woran liegt das?

    Noch unlogischer finde ich, dass bei der Änderung der Sichtbarkeit auf protected auf einmal alles wie erwartet funktioniert. Was hat das damit überhaupt zu tun?


  • #2
    Naja, grundlegend sagen ja private und protected ja etwas darüber aus, wie Methoden einer fremden (aber verwandten) Klasse auf eine Property eines Objektes zugreifen können. Von daher ist das Verhalten irgendwo nachvollziehbar, auch wenn ich es jetzt so nicht erwartet hätte. test() gehört A und soll auch B: zugreifen. Verletzt damit also die Sichtbarkeitsregeln. B::test() muss man sich also so vorstellen:

    PHP-Code:
    function test() {
      return 
    parent::test();

    Dann stimmt die Logik. parent ist A, $this in A::test() wird Instanz von A und hat demnach keinen Zugriff auf B:.

    Ehrlich gesagt verwende ich seit Jahren kein private mehr, weil ich die Möglichkeit eine Klasse zu erweitern eigentlich immer haben möchte. Ansonsten benutze ich lieber final.
    --

    „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
    Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


    --

    Kommentar


    • #3
      das ist ein normales Verhalten.
      Leider habe ich kein PHP5.3 laufen, aber dieser Code müsste unter 5.3 funktionieren:

      PHP-Code:
      <?php
      class {
          private 
      $x 'a';

          public function 
      test() {
              
      $className get_called_class();
              echo 
      $className->$x;
          }
      }

      class 
      extends {
          private 
      $x 'b';
      }
      $b = new B();
      $b->test();
      "My software never has bugs, it just develops random features."
      "Real programmers don't comment. If it was hard to write, it should be hard to understand!"

      Kommentar


      • #4
        Glaube ich aus mehreren Gründen nicht. Z.B. $x ist nicht statisch. Vielleicht hast DU das jetzt falsch verstanden. Es geht nicht um das static Verhalten!
        --

        „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
        Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


        --

        Kommentar


        • #5
          Danke für Eure Antworten.

          Ja, der Code von oben funktioniert leider nicht. Bei „echo $className->x“ (das $x war ein Tippfehler, oder?) gibt es gar keine Ausgabe, und bei „echo $className::$x“ die Fehlermeldung, dass das Attribut nicht statisch ist – wie nikosch ja schon geschrieben hat.

          Zitat von nikosch Beitrag anzeigen
          B::test() muss man sich also so vorstellen:

          PHP-Code:
          function test() {
            return 
          parent::test();

          Dann stimmt die Logik. parent ist A, $this in A::test() wird Instanz von A und hat demnach keinen Zugriff auf B:.
          Dass die Methode zu A gehört und quasi nur der Zugriff auf diese Methode an B vererbt wird, nicht die Methode selber, kann ich nachvollziehen. Was ich dann aber nicht verstehe:

          In der Methode gibt es ja dann überhaupt keinen Bezug mehr zu $b, sondern $this ist, wie Du schreibst, eine Instanz von A. Also die Methode bezieht sich rein auf A. Wenn man aber $x in beiden Fällen als protected festlegt, dann greift die Methode doch wieder auf $b zu, d. h., $this ist auf einmal doch eine Referenz auf $b.

          Komisch finde ich auch, dass dabei jetzt irgendwie Objekt-Zugriff und Klassen-Zugriff durcheinandergehen: Bei einer „normalen“ Klasse ohne irgendwelche geerbten Methoden/Attribute bezieht sich $this ja immer auf das jeweilige Objekt. Bei dem obigen Beispiel gibt es aber plötzlich einen Zugriff auf die Klasse A.

          Kommentar


          • #6
            Naja, ich habe geschrieben, man kann sich das so vorstellen. Technisch ist das sicher anders gelöst. Genau erklären kann ichs auch nicht, ist eher so eine Gefühlssache. Wie gesagt, ein bissel ungewöhnlich finde ich das Verhalten auch, wenn auch logisch.
            --

            „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
            Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


            --

            Kommentar


            • #7
              Private Methoden/Eigenschaften überschreiben nunmal nicht die der anderen, da sie für die anderen garnicht sichtbar sind. Entsprechend kann A nur auf die eigene Eigenschaft zugreifen. So ganz unlogisch ist das nicht, wenn man eben bedenkt, dass private eben der wirklich private Namespace nur dieser Klasse (und auch keiner verwandten Klassen) ist.

              Entsprechend ärgerlich sind eben auch Programmierer, die meinen private benutzen zu wollen, obwohl die Aktionen in keiner Weise privat sein sollten (sehe ich gelegentlich bei Zend). Faustregel muss eben heißen, dass grundsätzlich erstmal alles protected sein sollte, public sowieso nie (zumindest meiner Meinung nach) und private nur dann, wenn man Hilfsvariablen für Algorithmen (meinetwegen internes Caching, propertiesUpdated = true) verwendet, in denen selbst erbende Klassen nicht herumpfuschen sollen.

              Beispielsweise eine Klasse MyNamespace_Sort die von MyNamespace_Sort_Quicksort erbt. In Quicksort ist dann der eigentliche Sortieralgorithmus abgelegt, den die Klasse MyNamespace_Sort nicht zu interessieren hat. Wobei man auch hier sicherlich sagen könnte, dass eine MyNamespace_Sort_Quicksort_EvenFaster vielleicht doch gerne reingreifen würde. Im Zweifelsfall ist eben wirklich protected zu wählen.
              "Mein Name ist Lohse, ich kaufe hier ein."

              Kommentar


              • #8
                Da hast Du natürlich auch wieder recht. Das Beispiel mit den Arbeitsvariablen ist gut. Ansonsten müsste die x-te erbende Klasse ja immer alle Variablen deklarieren und geeignet initialisieren (vor allem auch das innere Variablenschema kennen), die die Ausgangsklasse vielleicht für Ihre Sortiermethode benötigt. So gesehen ist das Verhalten sehr sinnvoll.
                --

                „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


                --

                Kommentar


                • #9
                  Zitat von Chriz Beitrag anzeigen
                  Private Methoden/Eigenschaften überschreiben nunmal nicht die der anderen, da sie für die anderen garnicht sichtbar sind. Entsprechend kann A nur auf die eigene Eigenschaft zugreifen. So ganz unlogisch ist das nicht, wenn man eben bedenkt, dass private eben der wirklich private Namespace nur dieser Klasse (und auch keiner verwandten Klassen) ist.
                  Genau.

                  Mein Codebeispiel war auf statische Properties ausgelegt, habs irgendwie verpeilt... sorry. Aber bei statischen Aufrufen wäre dies die vorgehensweise.
                  "My software never has bugs, it just develops random features."
                  "Real programmers don't comment. If it was hard to write, it should be hard to understand!"

                  Kommentar


                  • #10
                    PHP-Code:
                    <?php
                    class {
                        protected 
                    $x 'a'//Eigenschaft ist vererbar

                        
                    protected function test() {
                           
                            return 
                    $this->x;
                        }
                    }

                    class 
                    extends {
                        
                    parrent::$x 'b'//Eigenschaft der Elternklasse mit einem wert belegen
                        
                    public function test(){
                        echo 
                    parent::test();
                    }
                    }
                    $b = new B();
                    $b->test();
                    meinstest du vllt das?

                    EDIT: genau dein beispiel findet man unter http://php.net/manual/de/keyword.parent.php
                    apt-get install npm -> npm install -g bower -> bower install <package> YOLO https://www.paypal.me/BlackScorp | Mein Youtube PHP Kanal: https://www.youtube.com/c/VitalijMik

                    Kommentar


                    • #11
                      Zitat von BlackScorp Beitrag anzeigen
                      PHP-Code:
                      <?php
                          parrent
                      ::$x 'b'//Eigenschaft der Elternklasse mit einem wert belegen
                      Da ist noch ein Rechtschreibfehler. parent
                      Damit würdest du dann 'A' bekommen.
                      "My software never has bugs, it just develops random features."
                      "Real programmers don't comment. If it was hard to write, it should be hard to understand!"

                      Kommentar


                      • #12
                        Zitat von Paul.Schramenko Beitrag anzeigen
                        Da ist noch ein Rechtschreibfehler. parent
                        Damit würdest du dann 'A' bekommen.
                        versuch du mal ohne fehler zu tippen, wenn du weist dass dein cheff jederzeit hinter dir stehen könnte und sehen würde dass du in forums rumdaddelst
                        apt-get install npm -> npm install -g bower -> bower install <package> YOLO https://www.paypal.me/BlackScorp | Mein Youtube PHP Kanal: https://www.youtube.com/c/VitalijMik

                        Kommentar


                        • #13
                          wenn ich das beispiel in #10 teste erhalte ich folgende fehlermeldung:

                          Parse error: syntax error, unexpected T_STRING, expecting T_FUNCTION

                          Kommentar


                          • #14
                            ok hier funktioniert das . anscheinend kann man parent:: nur auf methoden verweden, bei eigenschaften reicht ein $this-> also das $this-> bezieht sich nich nur auf eigene eigenschaften, sondern auch auf die eigenschaften der elternklasse, wenn du eine variable $x auch in B deklarierst, dann gibts probleme , weil eine eigenschaft doppelt vorhanden ist
                            PHP-Code:
                            <?php
                            class {
                                protected 
                            $x 'a'//Eigenschaft ist vererbar
                                
                            protected function test() {
                                    return 
                            $this->x;
                                }
                            };

                            class 
                            extends {
                                private 
                            $xB;
                                public function 
                            setVar($var){
                                    
                            $this->xB $var
                                }
                                public function 
                            test() {
                                    if(!empty(
                            $this->xB)) {
                                        
                            $this->$this->xB//da x bereits in A deklariert ist, kann man das x direkt mit $this ansprechen
                                    
                            }
                                    echo 
                            parent::test(); //Eigenschaft der eltern Klasse ausgeben
                                
                            }
                            };

                            $b = new B();
                            $b->test(); //a wird ausgegeben
                            $b->setVar('b'); 
                            $b->test(); //b wird ausgegeben
                            apt-get install npm -> npm install -g bower -> bower install <package> YOLO https://www.paypal.me/BlackScorp | Mein Youtube PHP Kanal: https://www.youtube.com/c/VitalijMik

                            Kommentar


                            • #15
                              Zitat von BlackScorp Beitrag anzeigen
                              versuch du mal ohne fehler zu tippen, wenn du weist dass dein cheff jederzeit hinter dir stehen könnte und sehen würde dass du in forums rumdaddelst
                              Dazu kann ich nur sagen das mein Chef mir auch schon über die Schulter geschaut hat während ich im Forum war. Ich erklärte Ihm dass ich öfter mal in dem Forum Hilfe Suche und auch bekomme. Und wer Hilfe erwartet sollte auch ruhig selbst mal anderen helfen.

                              Edit: Sorry für OT

                              Kommentar

                              Lädt...
                              X