Dynamiczne wywołanie metod klas w PHP

88

Czy istnieje sposób na dynamiczne wywołanie metody w tej samej klasie dla PHP? Nie mam prawidłowej składni, ale chcę zrobić coś podobnego do tego:

$this->{$methodName}($arg1, $arg2, $arg3);
VirtuosiMedia
źródło
Czy to było pierwotne pytanie? Szukałem dynamicznego wywoływania metody i znalazłem to pytanie. To ta sama składnia, którą podał andy.gurin i nie widzę linku, który pokazuje aktualizację pytania. W każdym razie ... Dzięki, że poprosiłem i dziękuję współpracownikom :-)
Luc M
5
@Luc - To było oryginalne pytanie. Okazuje się, że składnia była poprawna, gdy zapytałem, ale coś innego było nie tak z moim kodem, więc nie zadziałało.
VirtuosiMedia

Odpowiedzi:

176

Jest na to więcej niż jeden sposób:

$this->{$methodName}($arg1, $arg2, $arg3);
$this->$methodName($arg1, $arg2, $arg3);
call_user_func_array(array($this, $methodName), array($arg1, $arg2, $arg3));

Możesz nawet użyć odbicia api http://php.net/manual/en/class.reflection.php

andy.gurin
źródło
Myślę, że może miałem poprawną składnię, więc coś innego jest nie tak z moim kodem, ponieważ nie działa on całkiem poprawnie. Hmm ...
VirtuosiMedia
Słowo dla zmęczonego, jeśli twoje metody są wywoływane na obiektach i testowane za pomocą PHPUnit, call_user_func_arrayjest dla ciebie.
OK,
Ty mój przyjacielu, właśnie uratowałeś mi dzień! Dzwoniłem call_user_func_array($this->$name, ...)i zastanawiałem się, dlaczego to nie zadziała!
Pubudu Dodangoda
11

Po prostu pomiń szelki:

$this->$methodName($arg1, $arg2, $arg3);
Konrad Rudolph
źródło
10

Możesz użyć Overloading in PHP: Overloading

class Test {

    private $name;

    public function __call($name, $arguments) {
        echo 'Method Name:' . $name . ' Arguments:' . implode(',', $arguments);
        //do a get
        if (preg_match('/^get_(.+)/', $name, $matches)) {
            $var_name = $matches[1];
            return $this->$var_name ? $this->$var_name : $arguments[0];
        }
        //do a set
        if (preg_match('/^set_(.+)/', $name, $matches)) {
            $var_name = $matches[1];
            $this->$var_name = $arguments[0];
        }
    }
}

$obj = new Test();
$obj->set_name('Any String'); //Echo:Method Name: set_name Arguments:Any String
echo $obj->get_name();//Echo:Method Name: get_name Arguments:
                      //return: Any String
RodolfoNeto
źródło
3

Możesz także użyć call_user_func()icall_user_func_array()

Peter Bailey
źródło
3

Jeśli pracujesz w klasie w PHP, polecam użycie przeciążonej funkcji __call w PHP5. Możesz znaleźć odniesienie tutaj .

Zasadniczo __call robi dla funkcji dynamicznych to, co __set i __get robi dla zmiennych w OO PHP5.

Noah Goodrich
źródło
2

Nadal ważne po tylu latach! Upewnij się, że przycinasz $ methodName, jeśli jest to zawartość zdefiniowana przez użytkownika. Nie mogłem zmusić $ this -> $ methodName do działania, dopóki nie zauważyłem, że ma wiodącą spację.

Snapey
źródło
Jeśli jest to treść zdefiniowana przez użytkownika, upewnij się, że robisz znacznie więcej niż tylko przycinanie nazwy! Na przykład ... sprawdź bezpieczeństwo! ;)
Erk
Gdzieś w Internecie szczegółowo opisałem, jak przekonwertować wprowadzone przez użytkownika utf8 na znaki bezpieczne dla systemu Windows. QuickBooks przeprowadził mnie przez tę wyżymaczkę - i dlaczego QB nie jest już częścią sposobu, w jaki kończę sprzedaż ...
Chris K,
Czy naprawdę pozwalasz klientowi określić dane wejściowe, które dynamicznie wywołują niektóre metody? Brak mi słów
Mcsky
Oczywiście zweryfikowano i sprawdzono, czy klasa faktycznie zawiera taką nazwaną metodę. Istnieje wiele sposobów sprawdzenia wartości. To bije długie oświadczenie dotyczące przełącznika.
Snapey
1

W moim przypadku.

$response = $client->{$this->requestFunc}($this->requestMsg);

Korzystanie z PHP SOAP.

user46637
źródło
2
Nie jestem pewien, ale uważaj na kwestię bezpieczeństwa
tom10271
1

Możesz przechowywać metodę w jednej zmiennej za pomocą zamknięcia:

class test{        

    function echo_this($text){
        echo $text;
    }

    function get_method($method){
        $object = $this;
        return function() use($object, $method){
            $args = func_get_args();
            return call_user_func_array(array($object, $method), $args);           
        };
    }
}

$test = new test();
$echo = $test->get_method('echo_this');
$echo('Hello');  //Output is "Hello"

EDYCJA: wyedytowałem kod i teraz jest kompatybilny z PHP 5.3. Tutaj kolejny przykład

David
źródło