簡體   English   中英

如何從存儲在變量中的字符串調用 function?

[英]How to call a function from a string stored in a variable?

我需要能夠調用 function,但是 function 名稱存儲在一個變量中,這可能嗎? 例如:

function foo ()
{
    //code here
}

function bar ()
{
    //code here
}

$functionName = "foo";
// I need to call the function based on what is $functionName

我最喜歡的版本是內聯版本:

${"variableName"} = 12;

$className->{"propertyName"};
$className->{"methodName"}();

StaticClass::${"propertyName"};
StaticClass::{"methodName"}();

您也可以將變量或表達式放在方括號內!

解決方案:使用PHP7

注意:有關摘要版本,請參閱答案末尾的 TL;DR。

舊方法

更新:此處解釋的舊方法之一已被刪除。 其他方法的解釋請參考其他答案,這里不做贅述。 順便說一下,如果這個答案對你沒有幫助,你應該回來升級你的東西。 PHP 5.6 支持已於 2019 年 1 月結束(現在甚至不支持 PHP 7.2 和 7.3)。 有關詳細信息,請參閱支持的版本

正如其他人提到的,在 PHP5(以及較新的版本,如 PHP7)中,我們可以使用變量作為 function 名稱,使用call_user_func()call_user_func_array()等。

新方法

從 PHP7 開始,引入了新的方法:

注意: <something>括號內的所有內容都表示一個或多個表達式來構成某物,例如<function_name>表示構成 function 名稱的表達式。

動態 Function 呼叫:Function 即時姓名

我們可以在一個 go 中形成一個括號內的 function 名稱:

(<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()周圍的括號不是錯誤,但放置括號可使代碼更具可讀性。 但是,有時您不能這樣做,例如在使用. 操作員。 為了保持一致,我建議您始終使用括號。

動態 Function 調用:Callable Property

一個有用的例子是在對象的上下文中:如果你在屬性中存儲了一個可調用對象,你必須這樣調用它:

($object->{<property_name>})();

舉個簡單的例子:

// Suppose we're in a class method context
($this->eventHandler)();

顯然,將其稱為$this->eventHandler()是完全錯誤的:您的意思是調用名為eventHandler的方法。

動態方法調用:動態方法名稱

就像動態 function 調用一樣,我們可以對方法調用執行相同的方式,用大括號而不是圓括號括起來(對於額外的 forms,請導航至 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

注意:與前一種方法相比,使用此方法的好處是,您無需關心呼叫類型(即是否為 static)。

注意:如果您關心性能(和微優化),請不要使用此方法。 正如我測試的那樣,這種方法確實比其他方法慢(超過 10 倍)。

附加示例:使用匿名類

讓事情變得有點復雜,您可以結合使用匿名類和上述功能:

$bar = "SomeThing";

echo (new class {
    public function something()
    {
        return 512;
    }
})->{strtolower($bar)}(); // 512

TL;DR(結論)

一般在PHP7中,使用下面的forms都是可以的:

// Everything inside `<something>` brackets means one or more expressions
// to form something

// Dynamic function call via function name
(<function_name>)(arguments);

// Dynamic function call on a callable property
($object->{<property_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 talk

是的,有可能:

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()的路線 go 。 可以使用這兩種方法傳遞 arguments

$function_name = 'foobar';

$function_name(arg1, arg2);

call_user_func_array($function_name, array(arg1, arg2));

如果您呼叫的 function 屬於 object,您仍然可以使用其中任何一個

$object->$function_name(arg1, arg2);

call_user_func_array(array($object, $function_name), array(arg1, arg2));

但是,如果您打算使用$function_name()方法,那么測試 function 是否存在是個好主意,如果名稱是動態的

if(method_exists($object, $function_name))
{
    $object->$function_name(arg1, arg2);
}

晚了幾年,但這是現在最好的方式恕我直言:

$x = (new ReflectionFunction("foo"))->getClosure();
$x();

如果其他人被谷歌帶到這里,因為他們試圖在 class 中使用變量作為方法,下面是一個實際工作的代碼示例。 以上都不適合我的情況。 主要區別在於$c = & new...聲明中的&和在call_user_func中傳遞的&$c

我的具體情況是在實現某人的代碼時必須使用 colors 和來自 csscolor.php class 的兩個成員方法 lighten lighten()和 darken darken() 。無論出於何種原因,我希望相同的代碼能夠調用 lighten() 和 darken() 而不是比 select 更符合邏輯。 這可能是我頑固地不使用 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);

上面的嘗試會給出關於期望第二個參數(百分比)的方法的警告。

為了完整起見,您還可以使用eval()

$functionName = "foo()";
eval($functionName);

但是, call_user_func()是正確的方法。

動態 function 名稱和命名空間

只是在使用名稱空間時添加關於動態 function 名稱的一點。

如果您使用的是命名空間,則以下內容將不起作用,除非您的 function 在全局命名空間中:

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"

我在這里發布了另一個例子

使用 call_user_func function。

我從這個問題和答案中學到了什么。 謝謝大家!

假設我有這些變量和函數:

$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";
}
  1. 在沒有 arguments 的情況下撥打 function

     // Calling sayHello() call_user_func($functionName1);

    你好!

  2. 使用 1 個參數調用 function

     // Calling sayHelloTo("John") call_user_func($functionName2, $friend);

    親愛的約翰,你好!

  3. 使用 1 個或多個 arguments調用 function 如果您正在動態調用函數並且每個 function 具有不同數量的 arguments,這將很有用。這是我一直在尋找(並解決)的案例。 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);

    親愛的莎拉,你好嗎?

再見!

如果您在 object 上下文中嘗試動態調用 function,請嘗試如下代碼:

$this->{$variable}();

以下代碼可以幫助在 PHP 中寫入動態 function。現在 function 名稱可以通過變量“$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);
}

考慮到此處給出的一些出色答案,有時您需要做到精確。 例如。

  1. 如果 function 有返回值,例如(布爾值、數組、字符串、整數、浮點數等)。
  2. 如果function沒有返回值檢查
  3. 如果 function 存在

讓我們看看它對給出的一些答案的功勞。

Class Cars{
        function carMake(){
        return 'Toyota';
        }
        function carMakeYear(){
        return 2020;
        }
        function estimatedPriceInDollar{
        return 1500.89;
        }
        function colorList(){
        return array("Black","Gold","Silver","Blue");
        }
        function carUsage(){
        return array("Private","Commercial","Government");
        }
    function getCar(){
    echo "Toyota Venza 2020 model private estimated price is 1500 USD";
    }
 }

我們想檢查方法是否存在並動態調用它。

$method = "color List";
        $class = new Cars();
        //If the function have return value;
        $arrayColor = method_exists($class, str_replace(' ', "", $method)) ? call_user_func(array($this, $obj)) : [];
        //If the function have no return value e.g echo,die,print e.t.c
     $method = "get Car";
        if(method_exists($class, str_replace(' ', "", $method))){
        call_user_func(array($class, $method))
        }

謝謝

我想到的一種非常規方法是,除非您通過一些自行編寫的超超自治 AI 生成整個代碼,否則您想要“動態”調用的函數很可能已經在您的代碼中定義根據。 那么,為什么不只檢查字符串並執行臭名昭著的ifelse舞蹈來召喚……你明白我的意思了。

例如。

if($functionName == 'foo'){
  foo();
} else if($functionName == 'bar'){
  bar();
}

如果你不喜歡ifelse梯子的乏味,甚至可以使用switch-case

我知道在某些情況下“動態調用 function ”是絕對必要的(就像一些修改自身的遞歸邏輯)。 但是大多數日常瑣碎的用例都可以避免。

它消除了應用程序中的很多不確定性,同時讓您有機會在字符串與任何可用函數的定義不匹配時執行回退 function。 恕我直言。

我不知道為什么你必須使用它,對我來說聽起來不太好,但如果只有少量功能,你可以使用 if/elseif 結構。 我不知道是否可以直接解決。

像 $foo = "bar"; $測試=“富”; 回聲$$測試;

應該返回欄,你可以嘗試一下,但我認為這不適用於函數

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM