Tôi cần có khả năng gọi một hàm, nhưng tên hàm được lưu trong một biến, điều này có khả thi không? ví dụ:
hàm foo () { // mã ở đây } thanh chức năng () { // mã ở đây } $ functionName = "foo"; // tôi cần gọi hàm dựa trên $ functionName là gì
Tôi cần có khả năng gọi một hàm, nhưng tên hàm được lưu trong một biến, điều này có khả thi không? ví dụ:
hàm foo () { // mã ở đây } thanh chức năng () { // mã ở đây } $ functionName = "foo"; // tôi cần gọi hàm dựa trên $ functionName là gì
Câu trả lời:
is_callable
chức năng. Nó sẽ kiểm tra xem một biến có chứa thứ gì đó có thể được gọi là hàm hay không (có thể là tên của hàm, mảng chứa đối tượng và tên hàm hoặc hàm đóng / ẩn danh)
call_user_func(array('ClassName', 'method'), $args)
Phiên bản yêu thích của tôi là phiên bản nội tuyến:
${"variableName"} = 12;
$className->{"propertyName"};
$className->{"methodName"}();
StaticClass::${"propertyName"};
StaticClass::{"methodName"}();
Bạn cũng có thể đặt các biến hoặc biểu thức bên trong dấu ngoặc!
{"functionName"}();
không hợp pháp và sẽ đưa ra lỗi cú pháp.
Vâng, có thể:
function foo($msg) {
echo $msg."<br />";
}
$var1 = "foo";
$var1("testing 1,2,3");
Nguồn: http://www.onlamp.com/pub/a/php/2001/05/17/php_foundations.html?page=2
Như đã đề cập, có một số cách để đạt được điều này với phương pháp an toàn nhất có thể call_user_func()
hoặc nếu bạn phải, bạn cũng có thể đi theo lộ trình $function_name()
. Có thể truyền đối số bằng cả hai phương thức này.
$function_name = 'foobar';
$function_name(arg1, arg2);
call_user_func_array($function_name, array(arg1, arg2));
Nếu chức năng bạn đang gọi thuộc về một đối tượng, bạn vẫn có thể sử dụng một trong hai
$object->$function_name(arg1, arg2);
call_user_func_array(array($object, $function_name), array(arg1, arg2));
Tuy nhiên, nếu bạn định sử dụng $function_name()
phương thức này, có thể là một ý tưởng tốt để kiểm tra sự tồn tại của hàm nếu tên đó theo bất kỳ cách nào động
if(method_exists($object, $function_name))
{
$object->$function_name(arg1, arg2);
}
Trong trường hợp người khác được google đưa đến đây vì họ đang cố gắng sử dụng một biến cho một phương thức trong một lớp, bên dưới là một mẫu mã sẽ thực sự hoạt động. Không ai ở trên làm việc cho tình huống của tôi. Sự khác biệt chính là &
trong tuyên bố $c = & new...
và &$c
được thông qua call_user_func
.
Trường hợp cụ thể của tôi là khi triển khai mã của ai đó phải thực hiện bằng màu sắc và hai phương thức thành viên lighten()
và darken()
từ lớp csscolor.php. Vì bất kỳ lý do gì, tôi muốn có cùng một mã có thể gọi sáng hoặc tối hơn là chọn nó bằng logic. Đây có thể là kết quả của sự bướng bỉnh của tôi khi không chỉ sử dụng if-other hoặc để thay đổi mã gọi phương thức này.
$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);
Lưu ý rằng thử bất cứ điều gì với $c->{...}
không làm việc. Sau khi xem nội dung do người đọc đóng góp ở cuối trang php.net call_user_func
, tôi đã có thể ghép các phần trên lại với nhau. Ngoài ra, lưu ý rằng $params
vì một mảng không hoạt động với tôi:
// This doesn't work:
$params=Array($color,$percent);
$rtn=call_user_func( array(&$c,$lightdark),$params);
Nỗ lực trên này sẽ đưa ra cảnh báo về phương thức mong đợi đối số thứ 2 (phần trăm).
Một vài năm muộn, nhưng đây là cách tốt nhất bây giờ imho:
$x = (new ReflectionFunction("foo"))->getClosure();
$x();
Để hoàn thiện, bạn cũng có thể sử dụng eval () :
$functionName = "foo()";
eval($functionName);
Tuy nhiên, call_user_func()
là cách thích hợp.
eval
không phải là một giải pháp cho câu hỏi này.
Lưu ý: Đối với phiên bản tóm tắt, xem TL; DR ở cuối câu trả lời.
Cập nhật : Một trong những phương pháp cũ được giải thích ở đây đã bị xóa. Tham khảo các câu trả lời khác để giải thích về các phương pháp khác, nó không được đề cập ở đây. Nhân tiện, nếu câu trả lời này không giúp ích gì cho bạn, bạn nên quay lại nâng cấp công cụ của mình. Hỗ trợ PHP 5.6 đã kết thúc vào tháng 1 năm 2019 (hiện tại ngay cả PHP 7.0 và 7.1 cũng không được hỗ trợ). Xem các phiên bản được hỗ trợ để biết thêm thông tin.
Như những người khác đã đề cập, trong PHP5 (và cả trong các phiên bản mới hơn như PHP7), chúng ta có thể sử dụng các biến làm tên hàm, sử dụng call_user_func()
và call_user_func_array()
(cá nhân, tôi ghét các hàm đó), v.v.
Kể từ PHP7, có những cách mới được giới thiệu:
Lưu ý: Mọi thứ trong <something>
ngoặc có nghĩa là một hoặc nhiều biểu thức để tạo thành một cái gì đó, ví dụ: <function_name>
có nghĩa là các biểu thức tạo thành một tên hàm.
Chúng ta có thể sử dụng một hoặc nhiều biểu thức bên trong dấu ngoặc đơn làm tên hàm chỉ trong một lần, dưới dạng:
(<function_name>)(arguments);
Ví dụ:
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))()();
Lưu ý: Mặc dù loại bỏ các dấu ngoặc đơn xung quanh str_replace()
không phải là một lỗi, nhưng việc đặt dấu ngoặc đơn làm cho mã dễ đọc hơn. Tuy nhiên, đôi khi bạn không thể làm điều đó, ví dụ như trong khi sử dụng.
toán tử. Để thống nhất, tôi khuyên bạn nên đặt dấu ngoặc luôn.
Giống như các lệnh gọi hàm động, chúng ta có thể thực hiện tương tự với các lệnh gọi phương thức, được bao quanh bởi dấu ngoặc nhọn thay vì dấu ngoặc đơn (đối với các biểu mẫu bổ sung, điều hướng đến phần TL; DR):
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
Xem nó trong một ví dụ:
class Foo
{
public function another(): string
{
return "something";
}
}
$bar = "another thing";
(new Something())->{explode(" ", $bar)[0]}(); // something
Một cách thanh lịch hơn được thêm vào trong PHP7 là như sau:
[<object>, <method_name>](arguments);
[<class_name>, <method_name>](arguments); // Static calls only
Ví dụ:
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
Lưu ý: Lợi ích của việc sử dụng phương thức này so với phương pháp trước đó là, bạn không quan tâm đến loại cuộc gọi (nghĩa là nó có tĩnh hay không).
Làm cho mọi thứ hơi phức tạp, bạn có thể sử dụng kết hợp các lớp ẩn danh và các tính năng ở trên:
$bar = "SomeThing";
echo (new class {
public function something()
{
return 512;
}
})->{strtolower($bar)}(); // 512
Nói chung, trong PHP7, sử dụng các hình thức sau đây đều có thể:
// 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)
Dựa chủ yếu vào bài nói chuyện PHP này .
(expressions)->$bar()
Chỉ cần thêm một điểm về tên hàm động khi sử dụng không gian tên.
Nếu bạn đang sử dụng không gian tên, các mục sau sẽ không hoạt động trừ khi chức năng của bạn nằm trong không gian tên toàn cầu:
namespace greetings;
function hello()
{
// do something
}
$myvar = "hello";
$myvar(); // interpreted as "\hello();"
Bạn phải sử dụng call_user_func()
thay thế:
// if hello() is in the current namespace
call_user_func(__NAMESPACE__.'\\'.$myvar);
// if hello() is in another namespace
call_user_func('mynamespace\\'.$myvar);
Bổ sung câu trả lời của @Chris K nếu bạn muốn gọi phương thức của đối tượng, bạn có thể gọi nó bằng một biến duy nhất với sự trợ giúp của bao đóng:
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"
Tôi đã đăng một ví dụ khác ở đây
Giả sử tôi có các biến và hàm này:
$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";
}
Để gọi hàm không có đối số
// Calling sayHello()
call_user_func($functionName1);
Xin chào!
Để gọi hàm với 1 đối số
// Calling sayHelloTo("John")
call_user_func($functionName2, $friend);
John thân mến, xin chào!
Để gọi hàm với 1 hoặc nhiều đối số
Điều này sẽ hữu ích nếu bạn tự động gọi các hàm của mình và mỗi hàm có số lượng đối số khác nhau. Đây là trường hợp của tôi mà tôi đã tìm kiếm (và giải quyết). call_user_func_array
là chìa khóa
// 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);
Sarah thân mến, bạn có khỏe không?
Tạm biệt!
Sử dụng hàm call_user_func.
Mã sau có thể giúp viết hàm động trong PHP. bây giờ tên hàm có thể được thay đổi động theo biến '$ current_page'.
$current_page = 'home_page';
$function = @${$current_page . '_page_versions'};
$function = function() {
echo 'current page';
};
$function();
$function
biến mà không có lý do.
Cách dễ nhất để gọi một hàm một cách an toàn bằng cách sử dụng tên được lưu trữ trong một biến là,
//I want to call method deploy that is stored in functionname
$functionname = 'deploy';
$retVal = {$functionname}('parameters');
Tôi đã sử dụng như dưới đây để tạo các bảng di chuyển trong Laravel một cách linh hoạt,
foreach(App\Test::$columns as $name => $column){
$table->{$column[0]}($name);
}
Một cách tiếp cận khác thường xuất hiện trong đầu tôi là, trừ khi bạn đang tạo toàn bộ mã thông qua một số AI siêu tự trị tự viết , có nhiều khả năng các hàm mà bạn muốn gọi "động", đã được xác định trong mã của bạn căn cứ. Vậy tại sao không kiểm tra chuỗi và làm điều khét tiếngifelse
điệu nhảy để triệu tập ... bạn hiểu ý tôi.
ví dụ.
if($functionName == 'foo'){
foo();
} else if($functionName == 'bar'){
bar();
}
Thậm chí switch-case
có thể được sử dụng nếu bạn không thích mùi vị nhạt nhẽo của ifelse
thang.
Tôi hiểu rằng có những trường hợp " tự động gọi hàm " sẽ là một điều cần thiết tuyệt đối ( Giống như một số logic đệ quy tự sửa đổi ). Nhưng hầu hết các trường hợp sử dụng tầm thường hàng ngày chỉ có thể tránh được.
Nó loại bỏ rất nhiều sự không chắc chắn từ ứng dụng của bạn, đồng thời cho bạn cơ hội thực hiện chức năng dự phòng nếu chuỗi không khớp với bất kỳ định nghĩa nào của các hàm có sẵn. IMHO.
if (method_exists($functionName)) $functionName(); else //exception or handle
Tôi không biết tại sao bạn phải sử dụng nó, nghe có vẻ không tốt cho tôi chút nào, nhưng nếu chỉ có một lượng nhỏ chức năng, bạn có thể sử dụng cấu trúc if / otherif. Tôi không biết nếu một giải pháp trực tiếp là có thể.
một cái gì đó như $ foo = "thanh"; $ test = "foo"; kiểm tra tiếng vang $$;
nên trả về thanh, bạn có thể thử xung quanh nhưng tôi không nghĩ rằng nó sẽ hoạt động cho các chức năng