Ankündigung

Einklappen
Keine Ankündigung bisher.

Reflection Class ... wo wurde Methode deklariert?

Einklappen

Neue Werbung 2019

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

  • Reflection Class ... wo wurde Methode deklariert?

    Gegoogled habe ich ... und rumpropbiert auch, aber ich bin da wohl zu doof, und der Code, den ich gefunden hab, tut nicht ...

    Ich würde gerne über eine Reflection (new ReflectionMethod) ??? herausfinden, woe GENAU eine Methode einer Klasse deklariert wurde, also ob:

    - in einem Trait
    - in einer beerbten Klasse
    - in der Klasse selbst (z.B. "Überdeklariert" )

    Kann mir jemand auf die Sprünge helfen?

  • #2
    Du must dich von Klasse zu Klasse/Trait durchhangeln und dir immer die Methoden und Traits holen und vergleichen.
    Traits hab ich selbst noch nie gebraucht. Es war reine Neugier zu probieren, wie man an Traits rankommt.
    Das Resultat ist dieses kleine Schmalspur-Beispiel:
    PHP-Code:
    <?php
    require '../class/class.debug.php';

    trait 
    SayWorld {
        public function 
    sayHello() {
          echo 
    'hallo';   
        }
    }

    class 
    MyHelloWorld {
        use 
    SayWorld;
    }

    class 
    MyExtHelloWorld extends MyHelloWorld{
    }

    $rc = new ReflectionClass('MyExtHelloWorld');
    $methods $rc->getMethods();
    $traits $rc->getTraits();
    debug::write('MyExtHelloWorld methods,traits',$methods$traits);

    $className0 =  $methods[0]->class;
    $methodName0 =  $methods[0]->name;

    $rc2 = new ReflectionClass($className0);
    $methods $rc2->getMethods();
    $traits $rc2->getTraits();
    debug::write('className0,methods,traits',$className0,$methods$traits);

    $traitName reset($traits)->name;
    $rc3 = new ReflectionClass($traitName);
    $methods $rc3->getMethods();
    $traits $rc3->getTraits();
    debug::write('traitName,methods,traits',$traitName,$methods$traits);
    Ein Debugger bzw. eine Debug-Klasse welche eine übersichtliche Darstellung der Ausgaben liefert möchte ich für solche Übungen nicht missen.
    Ausgabe:

    debug_reflection.png

    LG jspit

    Kommentar


    • #3
      ja, ich habe das heute auch ausprogrammiert ...

      Nun gibt's bei Methoden aber ne ganze Reihe von Möglichkeiten, woher sie kommen:

      (1) in der Klasse "direkt" deklariert
      (2) in die Klasse per "use" aus einem Trait

      (3) in die Klasse vererbt
      (4) wie (3) aber unter Bedingung wie (2)


      Wobei rein Rekursionstechnisch (2), (3), und (4) denselben Auslese-Code benutzen können.


      Was bleibt, ist die Schwierigkeit, festzustellen, wo die in der Klasse letztendlich verwendete Methode nun genau deklariert wurde. Da gibts folgende Möglichkeiten:

      (A) in der Klasse, und kein Trait hatte eine gleichnamige Methode
      (B) aus einem Trait
      (C) in der Klasse, zusätzlich hatte aber einer (oder rekursiv mehrere)


      Ich habe den ganzen Tag probiert und gesucht, und leider nur eine umständliche Art gefunden, wie man sicher sein kann, dass eine Methode genau dort deklariert wurde, wo man es vermutet, nämlich in dem man die Properties
      filename, startline und endline mit der Methode in der Klasse ($C= new ReflectionClass; $C->getMethods(); --< Methode für Methode die Properties lesen) mit einem potenziellen Ort vergleicht,m und zwar immer dann, wenn diese Properties NICHT mit denen der Klasse übereinstimmen (filename identisch, Zeilen innerhalb der Zeilen der Klasse).

      Uff was 'n Umstand! wieso bringen die in der Methoden-Reflection nicht einfach den Namen, wo sie deklariert ist? getDeclarationParent() --> array mit Name und type (Class, Trait)???

      Man kriegt zwar über getDeclaringClass() IM FALLE DER VERERBUNG heraus, OB man in einer anderen Klasse weitersuchen muß (Name<>Name der untersuchten Klasse) aber nicht, wenn die Methode aus einem Trait stammt. Dann ist nämlich getDeclaringClass gleich der Klasse, in der der Trait benutzt wurde, also gerade so, als ob die Methode in der Klasse deklariert wurde.

      Strange!

      Kommentar


      • #4
        getMethods() liefert doch schon die Klasse, welche die Methode deklariert hat bzw. per Trait benutzt (s. Debuginfo Line20). In dieser Klasse must du nun abtesten, ob diese Traits benutzt. Wenn ja, hole dir die Methoden der/des Traits. Findest du dort den Namen deiner Methode, ist deine Methode in diesem Trait definiert. Wie hier im Beispiel, s. Debuginfo Line 34. Wenn nicht ist die Methode ganz normal in der Klasse definiert.
        Ein Zurückgreifen auf den Quellcode ist m.E. nicht notwendig. Geht auch nur bei eigenen Quellen, nicht wenn Klassen aus dem PHP-Kern im Spiel sind.

        Kommentar


        • #5
          (Leider) nur teilweise richtig.

          richtig: getMethods() lIefert jeweils die Klasse, wo die Deklaration bzw. use (ursprünglich) statt findet. AAAABER:

          1.) Eine Klasse kann zwar einen Trait (mit Methode "x") nutzen aber selbst eine gleichnamige Methode ("x") "überdefieren". In BEIDEN Fällen wird als Deklarationsort die Klasse benannt.
          2.) Ein Trait kann einen anderen Trait nutzen, also muß "x", selbst, wenn nicht in der Klasse (oder einem Parent) "überdeklariert", nicht zwingend aus dem ersten Trait kommen.

          Insofern muß also IMMER zunächst geprüft werden, ob die Methoden-Deklarations-Stelle jeder gefundenen Methode in der Klasse liegt oder nicht. Falls nicht, muß weitergesucht werden. Rekursiv, mit derselben Mechanik.

          Boah! Was'n Aufwand ... zumal die ja sowohl file als auch Line-of-Code bei den Properties der Methode speichern. Warum in aller Welt nicht auch den Namen des Trait/der Klasse ???

          Kommentar


          • #6
            Ok, für solche Fälle wie zuvor beschrieben, hast du Recht. Mal abgesehen davon, das ich selbst keine Traits benutze (da nicht vom echten Gewinn diese Konstruktes überzeugt), würde ich mir nie eine Methode per use in meine Klasse reinziehen um sie dann zu überschreiben.
            Das Ende der Fahnenstange ist aber mit einem Vergleich der start- und endlines noch nicht erreicht, wenn ich auch noch includes innerhalb von Klassen und Traits betrachten muss.

            Kommentar


            • #7
              naja, die includes machen da weniger Scherereien, weil ja bei der MEthod der Dateiname plus Zeilen abgerufen werden kann.

              Ich nutze traits sehr stark, weil mir das den flexiblen Aufbau von Klassen ermöglicht, was mit reiner so Vererbung nicht möglich ist ... wenn man sich nicht selbst eine Art pre-compiler baut, der aus verschiedenen code-Bestandteilen und -Versionen Basisklassen zusammenstellt.

              Und insofern macht dann auch das Überschreiben in einer Klasse wieder Sinn, wenn ich "ausnahmsweise" von vielen, sagen wir 50, Methoden nur eine oder zwei anders haben will. Dann wieder einen neuen Versions-Trait anzufangen führt schnell zu einem Trait-Chaos.

              Weiterer Vorteil von Traits ist, dass - in einem Framework - der User sich eigene Klassen individuell zusammenstellen kann. Im Prinzip sind Traits nichts anderes als Funktions-Libraries (in Zukunft mit Constanten auch noch ein bissl mehr).

              Kommentar


              • #8
                Zitat von jwka61 Beitrag anzeigen
                Im Prinzip sind Traits nichts anderes als Funktions-Libraries (in Zukunft mit Constanten auch noch ein bissl mehr).
                Warum verwendest du dann nicht gleich richtige Funktions-Libraries statt Traits?

                Kommentar


                • #9
                  Was sind Funktions-Libraries und kann ich dort auch Methoden einbringen, die in Klassen verwendet werden?

                  Kommentar


                  • #10
                    Zitat von jwka61 Beitrag anzeigen
                    Was sind Funktions-Libraries
                    Eine Ansammlung von Funktionen.

                    Zitat von jwka61 Beitrag anzeigen
                    und kann ich dort auch Methoden einbringen, die in Klassen verwendet werden?
                    Wozu? Du verwendest doch eh kein richtiges OOP. Wozu dann überhaupt Klassen?

                    Kommentar


                    • #11
                      Weil Klassen besser kapseln? Und auch Daten-Behälter sind/sein können? Weil dort Konstanten definiert werden können? Weil ich mit einer Klasse nur einen einzigen Namen im Namensraum blockiere? Weil damit ein leichtes vererben einer zusammengestellten Menge von Funktinen und Daten möglich ist?

                      Alles Gründe, die Du nicht gelten läßt, nehme ich an.

                      Und nu komm nicht mit Namespaces. Die gehen weder für Daten noch für Konstanten.

                      Kommentar


                      • #12
                        Zitat von jwka61 Beitrag anzeigen
                        Und nu komm nicht mit Namespaces. Die gehen weder für Daten noch für Konstanten.
                        Und das ist falsch.

                        Kommentar


                        • #13
                          Ok. dann habe ich da ne Wissenslücke.

                          Mein Stand:

                          Wenn ich ein namespace in einer include mache und dort Variablen definiere, sind diese in allen anderen namespaces unter genau demselben Namen verfüg- und überschreibbar, während funktionen nur unter "<namespace>\funktion()" verfügbar sind. Schützbar sind Variablen gar nicht.

                          Damit sind aber die Namen aller Variablen "blockiert" für andere User (im Falle eines Framework) oder die Nutzung (und ggf. das Überschreiben vitaler Werte) verursacht jedenfalls ggf. Scherereien im Framework.

                          Falls das falsch ist, bitte ich um Nachhilfe mit konkretem Code.

                          Danke.

                          Kommentar


                          • #14
                            Zitat von jwka61 Beitrag anzeigen
                            Wenn ich ein namespace in einer include mache und dort Variablen definiere, sind diese in allen anderen namespaces unter genau demselben Namen verfüg- und überschreibbar, während funktionen nur unter "<namespace>\funktion()" verfügbar sind. Schützbar sind Variablen gar nicht.

                            Damit sind aber die Namen aller Variablen "blockiert" für andere User (im Falle eines Framework) oder die Nutzung (und ggf. das Überschreiben vitaler Werte) verursacht jedenfalls ggf. Scherereien im Framework.
                            Du kannst auch Namespaces simulieren. War in PHP Gang und Gäbe, bevor Namespaces richtig unterstützt wurden.

                            PHP-Code:
                            $fooNamespace_$value 1;
                            $barNamespace_$value 2
                            Oder einfach Arrays verwenden:

                            PHP-Code:
                            $foo = [
                                
                            'value' => 1
                            ];

                            $bar = [
                                
                            'value' => 2
                            ]; 

                            Kommentar


                            • #15
                              Thema verfehlt. Sehr schwach!

                              Kommentar

                              Lädt...
                              X