Ankündigung

Einklappen
Keine Ankündigung bisher.

klasse::methode in Variable nutzen wie Funktion?

Einklappen

Neue Werbung 2019

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

  • klasse::methode in Variable nutzen wie Funktion?

    Hallo,

    ich habe mal wieder eine Frage, die vielleicht das eine oder andere Gemüt bewegt und trau mich trotzdem. Darf ich die Puristen und Profis bitten, das ganze mal rein wissenschaftlich zu betrachten, also nicht unter den Gesichtspunkten "macht man / ist schlechter Stil / geht in die Hose" sondern "geht grundsätzlich / geht nicht". Danke vorab.

    Also:


    Es gibt ja die Möglichkeit, eine Variable mit einem Funtionsnamen zu befüllen und diese Variable dann als Ersatz für die Funktion zu benutzen, mit dem Ergebnis, dass man in ein und derselben Codezeile unterschiedliche Funktionen aufrufen würde (ok. ich weis, das ist "unpflegbar" ... wissenschaftlich ... trotzdem

    Fall 1
    PHP-Code:
         function X()
         { echo 
    __FUNCTION__ "\n"; }


         function 
    Y()
         { echo 
    __FUNCTION__ "\n"; }


         
    $var="x";
         
    $var();

         
    $var="Y";
         
    $var() 
    Nun frage ich mich - rein wissenschaftlich - warum dasselbe nicht auch mit "Klasse::Methode" geht, wohl aber Klasse::$var_mit_methodenname(). Warum also geht folgendes:
    Fall 2
    PHP-Code:
       abstract class A
       
    {
         public static function 
    X()
         { echo 
    __METHOD__ "\n"; }


         public static function 
    Y()
         { echo 
    __METHOD__ "\n"; }
       }


         
    $var="x";
         
    A::$var();

         
    $var="Y";
         
    A::$var(); 

    und es geht auch folgendes:
    Fall 3
    PHP-Code:
       abstract class A
       
    {
         public static function 
    X()
         { echo 
    __METHOD__ "\n"; }


         public static function 
    Y()
         { echo 
    __METHOD__ "\n"; }
       }

         
    $class="A";

         
    $var="x";
         
    $class::$var();

         
    $var="y";
         
    $class::$var(); 

    aber folgendes geht nicht:
    Fall 4
    PHP-Code:
       abstract class A
       
    {
         public static function 
    X()
         { echo 
    __METHOD__ "\n"; }


         public static function 
    Y()
         { echo 
    __METHOD__ "\n"; }
       }


         
    $var="A::x";
         
    $var();

         
    $var="A::y";
         
    $var(); 
    Wenn wir nun mal vom allgemeinen "macht man nicht" absehen, es würde mich schon interessieren, ob man mit irgendwelchern Mittel, wie geschweiften Klammern etc. Fall 4 doch zum funktionieren überreden kann. Dieser Fall ist ja keinen Deut schlechter als Fall 3, würde aber das umständliche getrennt halten und zuweisen der Klasse in eine eigene Variable ersparen.

    Gespannt ...


    Ich muss PHP im Kontext Home Automation nutzen (Vorgabe Hersteller und nicht zu ändern). Da kommt es leider ggf. auf ms an. Deshalb manche "seltsame" Frage.

  • #2
    aber folgendes geht nicht:
    weil '::' ein String ist und nicht der Operator.

    Kommentar


    • #3
      String-Aufrufe kann man in PHP als so genannte callables definieren. Objekte bzw. Klassen mit statischen Methoden werden dabei als Array verwendet, in der das erste Element die Klasse / das Objekt ist und das zweite der Methodenname als String. Folgendes Funktioniert also (es wird "test" ausgegeben):

      PHP-Code:
      <?php  
      class {    
          public static function 
      test() {      
              echo 
      "test";    
          }
      }  
       
      $callable = ["A""test"];
      // Ruft A::test(); auf
      call_user_func($callable, []);
      Tutorials zum Thema Technik:
      https://pilabor.com
      https://www.fynder.de

      Kommentar


      • #4
        Fun Fact: in PHP7 scheint es wie in "Fall 4" zu gehen.
        [QUOTE=nikosch]Macht doch alle was Ihr wollt mit Eurem Billigscheiß. Von mir aus sollen alle Eure Server abrauchen.[/QUOTE]

        Kommentar


        • #5
          Wenn wir nun mal vom allgemeinen "macht man nicht" absehen, es würde mich schon interessieren, ob man mit irgendwelchern Mittel, wie geschweiften Klammern etc. Fall 4 doch zum funktionieren überreden kann. Dieser Fall ist ja keinen Deut schlechter als Fall 3, würde aber das umständliche getrennt halten und zuweisen der Klasse in eine eigene Variable ersparen.
          explode(); mit '::'' als Delimiter um an Klasse und Methode zu kommen.
          [COLOR=#A9A9A9]Relax, you're doing fine.[/COLOR]
          [URL="http://php.net/"]RTFM[/URL] | [URL="http://php-de.github.io/"]php.de Wissenssammlung[/URL] | [URL="http://use-the-index-luke.com/de"]Datenbankindizes[/URL] | [URL="https://www.php.de/forum/webentwicklung/datenbanken/111631-bild-aus-datenbank-auslesen?p=1209079#post1209079"]Dateien in der DB?[/URL]

          Kommentar


          • #6
            Zitat von VPh Beitrag anzeigen
            explode(); mit '::'' als Delimiter um an Klasse und Methode zu kommen.
            das kann man dann auch gleich so in call_user_func() stecken.

            Kommentar


            • #7
              Stimmt. So was hier
              PHP-Code:
              $fk "A::X";
              call_user_func($fk); 
              funktioniert sogar schon ab PHP 5.3.

              Ab PHP 7 auch
              PHP-Code:
              $fk "A::X";
              $fk(); 

              Kommentar


              • #8
                Dormilich & @jspit: Ich kenne call_user_func. Das ist NICHT dasselbe. Wenn man nämlich in "tieferen Ebenen" z.B. mit debug_backtrace() arbeitet, ist der gesuchte Aufruf-Code "eine Stufe höher" asl in meinen Beispielen (und dem "direkten code" A :: X() )

                @tkausl: Das ist in der Tat interessant. Muss ich also mal auf V7 warten (bei mir - eingebettet in das Wirtssystem - rennt noch V5)
                Ich muss PHP im Kontext Home Automation nutzen (Vorgabe Hersteller und nicht zu ändern). Da kommt es leider ggf. auf ms an. Deshalb manche "seltsame" Frage.

                Kommentar


                • #9
                  V7 warten ?? das gibts doch bereits ... schau dir mal Xampp an - du hast derzeit die Auswahl PHP 5.5 , PHP 5.6 , PHP 7.0

                  "Irren ist männlich", sprach der Igel und stieg von der Drahtbürste [IMG]http://www.php.de/core/images/smilies/icon_lol.gif[/IMG]

                  Kommentar


                  • #10
                    jwka61
                    explode(); mit '::'' als Delimiter um an Klasse und Methode zu kommen.
                    works, not works, passt nicht zum Stil?

                    [COLOR=#A9A9A9]Relax, you're doing fine.[/COLOR]
                    [URL="http://php.net/"]RTFM[/URL] | [URL="http://php-de.github.io/"]php.de Wissenssammlung[/URL] | [URL="http://use-the-index-luke.com/de"]Datenbankindizes[/URL] | [URL="https://www.php.de/forum/webentwicklung/datenbanken/111631-bild-aus-datenbank-auslesen?p=1209079#post1209079"]Dateien in der DB?[/URL]

                    Kommentar


                    • #11
                      Sind halt leider auch wieder mehrere Zwischenschritte nötig, weil "$ex[0]::$x[1]()" ja auch nicht akzeptiert wird ... . Deshalb müßte ich $ex=explode(); $C=$ex[0]; $f=$ex[1]; $C::$f schreiben ... das ist im code als Argument einer Funktion ziemlich fett ... ich suche halt nach einer möglichst kurzen Variante ...

                      @eagle275: "bei mir - eingebettet in das Wirtssystem - rennt noch V5" Ich kann (noch) nicht einfach den PHP Interpreter updaten, weil der Bestandteil eines ganzen Systems ist, das ich (noch) nutze.
                      Ich muss PHP im Kontext Home Automation nutzen (Vorgabe Hersteller und nicht zu ändern). Da kommt es leider ggf. auf ms an. Deshalb manche "seltsame" Frage.

                      Kommentar


                      • #12
                        Was zumindest in PHP 5.6 funktioniert, sind Objekte der Klasse \Closure. Die lassen sich in Variablen packen und genauso wie variable Funktionen verwenden. Glücklicherweise lassen sich Closure-Objekte aus jedem bekannten Callable-Typ herstellen. Um nicht jedesmal das gesammelte Reflection-Geraffel einzutippen, hab ich mir dazu eine Utility-Funktion gebastelt:

                        PHP-Code:
                        use MyTypeError// extends \ArgumentException (or whatever suits your needs)

                        function ClosureFromCallable(
                            
                        $callback /// every callable type
                        ) {
                            
                        // note: callable() type hint may not work on array($this, 'method') arguments
                            
                        if ($callback instanceof \Closure) {
                                return 
                        $callback;
                            }
                            
                        // member function (of an object or of a class)
                            
                        if (is_array($callback)) {
                                return 
                        is_object($callback[0])
                                    ? (new \
                        ReflectionMethod($callback[0], $callback[1]))->getClosure($callback[0]) // obj->method()
                                    
                        : (new \ReflectionMethod($callback[0], $callback[1]))->getClosure(); // class::method()
                            
                        }
                            
                        // str()
                            // function literal (includes functions declared with create_function())
                            
                        if (!is_int(strrpos($callback'::', -1))) {
                                return (new \
                        ReflectionFunction($callback))->getClosure(); // from create_function or \Closure::
                            
                        }
                            
                        // class member function as string literal
                            
                        $m = new \ReflectionMethod($callback);
                            if (
                        $m->isStatic()) {
                                return 
                        $m->getClosure(); // str('classname::method')
                            
                        }
                            throw new 
                        MyTypeError('object method given, but only class methods allowed'); // object method

                        Angewandt funktioniert dann auch dein Beispiel 4:
                        PHP-Code:
                        abstract class {
                            public static function 
                        X() {
                                echo 
                        __METHOD__ "\n";
                            }
                        }

                        $var ClosureFromCallable(__NAMESPACE__ '\A::x');
                        $var(); 
                        Im Gegensatz zu call_user_func() und Kumpels wird dabei auch der Call-Stack nicht zugemüllt.

                        Ein weiterer Vorteil: Du kannst Closures "type-hinten", also in Funktionsdeklarationen \Closure als Parameter-Typ angeben.

                        Update: Seit PHP 7.1 hat die Closure-Klasse eine Methode ::fromCallable(), die prinzipiell das Gleiche tut. Die Idee stammt vom April 2016.
                        Wenn man die Wurst schräg anschneidet, hält sie länger, weil die Scheiben größer sind.

                        Kommentar


                        • #13
                          abgesehen davon, dass ich ohne Funktionen auskommen wollte (wenn schon, dann klassen) werde ich mir das mal genauer ansehen. Scheint ein interessanter Ansatz.

                          Danke für Euren Input.
                          Ich muss PHP im Kontext Home Automation nutzen (Vorgabe Hersteller und nicht zu ändern). Da kommt es leider ggf. auf ms an. Deshalb manche "seltsame" Frage.

                          Kommentar

                          Lädt...
                          X