ฉันต้องสามารถเรียกใช้ฟังก์ชั่นได้ แต่ชื่อฟังก์ชั่นนั้นถูกเก็บไว้ในตัวแปรเป็นไปได้หรือไม่? เช่น:
ฟังก์ชั่น foo () { // รหัสที่นี่ } แถบฟังก์ชั่น () { // รหัสที่นี่ } $ functionName = "foo"; // ฉันต้องเรียกใช้ฟังก์ชันตาม $ functionName
ฉันต้องสามารถเรียกใช้ฟังก์ชั่นได้ แต่ชื่อฟังก์ชั่นนั้นถูกเก็บไว้ในตัวแปรเป็นไปได้หรือไม่? เช่น:
ฟังก์ชั่น foo () { // รหัสที่นี่ } แถบฟังก์ชั่น () { // รหัสที่นี่ } $ functionName = "foo"; // ฉันต้องเรียกใช้ฟังก์ชันตาม $ functionName
คำตอบ:
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);
ความพยายามด้านบนนี้จะให้คำเตือนเกี่ยวกับวิธีการที่คาดว่าจะมีอาร์กิวเมนต์ที่สอง (เปอร์เซ็นต์)
ไม่กี่ปีที่ผ่านมา แต่นี่เป็นวิธีที่ดีที่สุดในตอนนี้ imho:
$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);
เรียน John, สวัสดี!
ในการเรียกใช้ฟังก์ชันที่มีอาร์กิวเมนต์ตั้งแต่ 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
บันได
ฉันเข้าใจว่ามีบางกรณีที่ "การเรียกใช้ฟังก์ชันแบบไดนามิก " จะเป็นสิ่งจำเป็นอย่างยิ่ง ( เช่นตรรกะแบบเรียกซ้ำซึ่งแก้ไขตัวเอง ) แต่กรณีการใช้งานเล็กน้อยในชีวิตประจำวันส่วนใหญ่สามารถหลบได้
มันกำจัดความไม่แน่นอนจำนวนมากออกจากแอปพลิเคชันของคุณในขณะที่ให้โอกาสคุณเรียกใช้ฟังก์ชันทางเลือกหากสตริงไม่ตรงกับคำจำกัดความของฟังก์ชันที่มี IMHO
if (method_exists($functionName)) $functionName(); else //exception or handle
ฉันไม่รู้ว่าทำไมต้องใช้สิ่งนั้นฟังดูไม่ดีสำหรับฉันเลย แต่ถ้ามีฟังก์ชั่นเพียงเล็กน้อยคุณสามารถใช้ a / if ถ้าสร้าง ฉันไม่รู้ว่าจะสามารถแก้ปัญหาโดยตรงได้หรือไม่
บางอย่างเช่น $ foo = "bar"; $ test = "foo"; echo $$ test;
ควรกลับแถบคุณสามารถลอง แต่ฉันไม่คิดว่ามันจะทำงานสำหรับฟังก์ชั่น