Відповіді:
is_callable
функцію. Він перевірить, чи містить змінна щось, що можна викликати як функцію (будь то ім'я функції, масив, що містить екземпляр об'єкта та ім'я функції, або анонімну функцію / закриття)
call_user_func(array('ClassName', 'method'), $args)
Моя улюблена версія - вбудована версія:
${"variableName"} = 12;
$className->{"propertyName"};
$className->{"methodName"}();
StaticClass::${"propertyName"};
StaticClass::{"methodName"}();
Ви також можете розміщувати змінні чи вирази всередині дужок!
{"functionName"}();
не є законним і призведе до помилки синтаксису.
Так, можливо:
function foo($msg) {
echo $msg."<br />";
}
$var1 = "foo";
$var1("testing 1,2,3");
Джерело: http://www.onlamp.com/pub/a/php/2001/05/17/php_foundations.html?page=2
Як уже згадувалося, є кілька способів досягти цього за допомогою, можливо, найбезпечнішого методу, call_user_func()
або, якщо вам потрібно, ви також можете спуститися по маршруту $function_name()
. Можна передавати аргументи, використовуючи обидва ці методи
$function_name = 'foobar';
$function_name(arg1, arg2);
call_user_func_array($function_name, array(arg1, arg2));
Якщо функція, яку ви викликаєте, належить об'єкту, ви все одно можете використовувати будь-яку з них
$object->$function_name(arg1, arg2);
call_user_func_array(array($object, $function_name), array(arg1, arg2));
Однак якщо ви збираєтесь скористатися $function_name()
методом, можливо, буде гарною ідеєю перевірити наявність функції, якщо ім'я будь-яким чином динамічне
if(method_exists($object, $function_name))
{
$object->$function_name(arg1, arg2);
}
Якщо хтось інший приведе сюди google через те, що вони намагалися використовувати змінну для методу в класі, нижче наведений зразок коду, який насправді спрацює. Ніщо з вищезазначеного не спрацювало для моєї ситуації. Ключова відмінність полягає &
в оголошенні $c = & new...
та &$c
передачі call_user_func
.
Мій конкретний випадок - це коли реалізувати чийсь код, що стосується кольорів та двох методів-членів lighten()
та darken()
класу csscolor.php. З будь-якої причини я хотів, щоб той самий код міг викликати полегшення або затемнення, а не вибирати його логікою. Це може бути наслідком моєї впертості не просто використовувати if-else або змінювати код, що викликає цей метод.
$lightdark="lighten"; // or optionally can be darken
$color="fcc"; // a hex color
$percent=0.15;
include_once("csscolor.php");
$c = & new CSS_Color($color);
$rtn=call_user_func( array(&$c,$lightdark),$color,$percent);
Зауважте, що спробувати що-небудь із цим $c->{...}
не вийшло. Коли я ознайомився з вмістом, прочитаним читачем, внизу сторінки php.net call_user_func
, я зміг зібрати вищезазначене. Також зауважте, що $params
масив не працював для мене:
// This doesn't work:
$params=Array($color,$percent);
$rtn=call_user_func( array(&$c,$lightdark),$params);
Ця вище спроба подасть попередження про метод, який очікує 2-го аргументу (відсотки).
Кілька років пізно, але це найкращий спосіб зараз:
$x = (new ReflectionFunction("foo"))->getClosure();
$x();
Для повноти ви також можете використовувати eval () :
$functionName = "foo()";
eval($functionName);
Однак call_user_func()
це правильний шлях.
eval
не є вирішенням цього питання.
Примітка. Для узагальненої версії див. TL; DR в кінці відповіді.
Оновлення : Один із описаних тут старих методів видалено. Зверніться до інших відповідей для пояснення щодо інших методів, тут це не висвітлено. До речі, якщо ця відповідь не допоможе вам, вам слід повернутися до оновлення своїх речей. Підтримка PHP 5.6 закінчилася в січні 2019 року (зараз навіть PHP 7.0 і 7.1 не підтримуються). Додаткову інформацію див. У підтримуваних версіях .
Як згадували інші, у PHP5 (а також у нових версіях, таких як PHP7) ми могли б використовувати змінні як назви функцій, використання call_user_func()
та call_user_func_array()
(що особисто я ненавиджу ці функції) тощо.
Станом на PHP7, існують нові способи:
Примітка: Все, що знаходиться в <something>
дужках, означає один або кілька виразів для формування чогось, наприклад, <function_name>
означає вирази, що утворюють ім’я функції.
Ми можемо використовувати один або декілька виразів у дужках як ім'я функції лише за один перехід у вигляді:
(<function_name>)(arguments);
Наприклад:
function something(): string
{
return "something";
}
$bar = "some_thing";
(str_replace("_", "", $bar))(); // something
// Possible, too; but generally, not recommended, because makes your code more complicated
(str_replace("_", "", $bar))()();
Примітка. Хоча видалення круглих дужок навколо str_replace()
не є помилкою, розміщення дужок робить код більш читабельним. Однак іноді цього не можна робити, наприклад, використовуючи .
оператор. Щоб бути послідовним, рекомендую завжди ставити круглі дужки.
Як і динамічні виклики функцій, ми можемо робити те саме, що і з викликами методів, оточених фігурними дужками замість дужок (для додаткових форм перейдіть до розділу TL; DR):
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
Дивіться це на прикладі:
class Foo
{
public function another(): string
{
return "something";
}
}
$bar = "another thing";
(new Something())->{explode(" ", $bar)[0]}(); // something
Більш елегантний спосіб, доданий у PHP7, полягає в наступному:
[<object>, <method_name>](arguments);
[<class_name>, <method_name>](arguments); // Static calls only
Як приклад:
class Foo
{
public function nonStaticCall()
{
echo "Non-static call";
}
public static function staticCall()
{
echo "Static call";
}
}
$x = new X();
[$x, "non" . "StaticCall"](); // Non-static call
[$x, "static" . "Call"](); // Static call
Примітка . Перевага використання цього методу над попереднім полягає в тому, що вам не байдужий тип дзвінка (тобто статичний він чи ні).
Зробити щось трохи складніше, ви можете використовувати комбінацію анонімних класів та вищезазначених функцій:
$bar = "SomeThing";
echo (new class {
public function something()
{
return 512;
}
})->{strtolower($bar)}(); // 512
Як правило, в PHP7 можливе використання наступних форм:
// Everything inside `<something>` brackets means one or more expressions
// to form something
// Dynamic function call
(<function_name>)(arguments)
// Dynamic method call on an object
$object->{<method_name>}(arguments)
$object::{<method_name>}(arguments)
// Dynamic method call on a dynamically-generated object
(<object>)->{<method_name>}(arguments)
(<object>)::{<method_name>}(arguments)
// Dynamic method call, statically
ClassName::{<method_name>}(arguments)
(<class_name>)::{<method_name>}(arguments)
// Dynamic method call, array-like (no different between static and non-static calls
[<object>, <method_name>](arguments)
// Dynamic method call, array-like, statically
[<class_name>, <method_name>](arguments)
В основному на цій розмові PHP .
(expressions)->$bar()
Просто додайте крапку про імена динамічних функцій при використанні просторів імен.
Якщо ви використовуєте простори імен, наступне не працюватиме, за винятком випадків, коли ваша функція знаходиться у глобальному просторі імен:
namespace greetings;
function hello()
{
// do something
}
$myvar = "hello";
$myvar(); // interpreted as "\hello();"
Ви повинні використовувати call_user_func()
замість цього:
// if hello() is in the current namespace
call_user_func(__NAMESPACE__.'\\'.$myvar);
// if hello() is in another namespace
call_user_func('mynamespace\\'.$myvar);
Доповнюючи відповідь @Chris K, якщо ви хочете викликати метод об’єкта, ви можете викликати його за допомогою єдиної змінної за допомогою закриття:
function get_method($object, $method){
return function() use($object, $method){
$args = func_get_args();
return call_user_func_array(array($object, $method), $args);
};
}
class test{
function echo_this($text){
echo $text;
}
}
$test = new test();
$echo = get_method($test, 'echo_this');
$echo('Hello'); //Output is "Hello"
Я розмістив тут ще один приклад
Скажімо, у мене є ці змінні та функції:
$functionName1 = "sayHello";
$functionName2 = "sayHelloTo";
$functionName3 = "saySomethingTo";
$friend = "John";
$datas = array(
"something"=>"how are you?",
"to"=>"Sarah"
);
function sayHello()
{
echo "Hello!";
}
function sayHelloTo($to)
{
echo "Dear $to, hello!";
}
function saySomethingTo($something, $to)
{
echo "Dear $to, $something";
}
Для виклику функції без аргументів
// Calling sayHello()
call_user_func($functionName1);
Привіт!
Для виклику функції з 1 аргументом
// Calling sayHelloTo("John")
call_user_func($functionName2, $friend);
Шановний Джон, привіт!
Для виклику функції з 1 або більше аргументів
Це буде корисно, якщо ви динамічно викликаєте свої функції і кожна функція має різну кількість аргументів. Це мій випадок, який я шукав (і вирішував). call_user_func_array
є ключовим
// You can add your arguments
// 1. statically by hard-code,
$arguments[0] = "how are you?"; // my $something
$arguments[1] = "Sarah"; // my $to
// 2. OR dynamically using foreach
$arguments = NULL;
foreach($datas as $data)
{
$arguments[] = $data;
}
// Calling saySomethingTo("how are you?", "Sarah")
call_user_func_array($functionName3, $arguments);
Дорога Сара, як справи?
До побачення!
Використовуйте функцію call_user_func.
Наступний код може допомогти написати динамічну функцію в PHP. тепер ім'я функції можна динамічно змінити змінною '$ current_page'.
$current_page = 'home_page';
$function = @${$current_page . '_page_versions'};
$function = function() {
echo 'current page';
};
$function();
$function
змінну без будь-яких причин.
Найпростіший спосіб безпечно викликати функцію за допомогою імені, збереженого в змінній,
//I want to call method deploy that is stored in functionname
$functionname = 'deploy';
$retVal = {$functionname}('parameters');
Як я описав нижче, я динамічно створював таблиці міграції в Laravel,
foreach(App\Test::$columns as $name => $column){
$table->{$column[0]}($name);
}
Один нетрадиційний підхід, який мені прийшов на думку, полягає в тому, що, якщо ви не генеруєте весь код через якийсь супер ультра автономний AI, який пише сам , є великі шанси, що функції, які ви хочете "динамічно" викликати, вже визначені у вашому коді база. То чому б просто не перевірити на струну і не зробити сумнозвісний ifelse
танець, щоб викликати ... ви зрозумієте мою думку.
напр.
if($functionName == 'foo'){
foo();
} else if($functionName == 'bar'){
bar();
}
Навіть switch-case
можна використовувати, якщо вам не подобається ніжний смак ifelse
сходів.
Я розумію, що є випадки, коли " динамічно викликає функцію " було б абсолютно необхідним ( як і деяка рекурсивна логіка, яка сама модифікує ). Але більшість випадкових тривіальних випадків використання можна просто ухилитись.
Це усуває велику невпевненість у вашій програмі, надаючи вам можливість виконати резервну функцію, якщо рядок не відповідає жодному з доступних визначень функцій. ІМХО.
if (method_exists($functionName)) $functionName(); else //exception or handle
Я не знаю, чому ви повинні використовувати це, не звучить мені так добре, але якщо є лише невелика кількість функцій, ви можете використовувати конструкцію if / elseif. Я не знаю, чи можливе пряме рішення.
щось на зразок $ foo = "бар"; $ test = "foo"; echo $$ test;
слід повернути панель, ви можете спробувати, але я не думаю, що це буде працювати для функцій