ARES資通電子報

技術交流

HCP技術交流-Dynamic Function Calling in PHP5

文 -Dennis

引言
在程式設計中,特別是在框架 (Framework) 的設計中,因為框架的設計者預先並不知道框架的使用者 (Programmer) 在程序撰寫時所命名的 Function 的名稱,框架的設計者可以用動態Function 的調用的方式來解決這個問題。簡單的說,就是 function 的名稱是一個變數。

開始
在本文中我們將會討論三種不同的動態調用的方式:
1.直接調用變數名稱,變數的值是一個 Function 的名稱
2.使用用 built-in Function call_user_func()
3.使用 built-in Function eval()

Variable Function
現舉例來說明什麼時機下我們用這種方式。在 MVC 模式中的 Model 中,假設是跟 Database 交互的,其中有 add/delete/update/query function,在實際調用時,因為不知道當前使用者(End-user) 要做的動作,這時就可以利用變量 Function 的方式來處理這樣的情景。當然也可以用 switch 的方式來處理。
<?php
  Class User{
    function __constuct()
    {
      // some code here
    }
      public function add()
{
      // some code here
}// end add()
public function update()
{
// some code here
}// end update()

public function delete()
{
  // some code here
}// end delete()
public function query()
{
  // some code here
}// end query()
}// end class User
?>
以下採用 switch 和動態 Function 調用代碼有何不同?
Switch
<?php
  include_once('User.php');
  $user = new User();
  $action = isset($_GET['action']) && !empty($_GET['action']) ?
        $_GET['action'] :
        'query';
switch ($action)
{
  case 'save':
    $user->save();
    break;
  case 'update':
    $user->update();
    break;
  case 'delete':
    $user->delete();
    break;
  case 'query':
    $user->query();
    break;
   default:break;
  }
?>
Dynamic Function Call
<?php
include_once('User.php');
$user = new User();
$action = isset($_GET['action']) && !empty($_GET['action']) ?
      $_GET['action'] :
      'query';
$user->$action();
?>
從上面的代碼片段可以看出,使用動態 Function 調用的代碼非常簡潔。
call_user_func()
第一種方式:第一個 Parameter 是 Function 的名稱,第二個 Parameter 就是 Function 的Parameter。
<?php
//Call a user defined function given by the function parameter.
// Take the following:

function hello($name)
{
  echo 'Hello '.$name;
}
call_user_func('hello', 'dennis'); //output "Hello dennis"
?>
第二種方式:靜態的方式直接調用物件的方法。
<?php
// Object methods may also be invoked statically using this function // by passing array($objectname, $methodname)
// to the function parameter.

class Hello {
  function say_hello()
  {
   echo "Hello!\n";
}
}
$classname = "Hello";
call_user_func(array($classname, 'say_hello'));
?>
這裡的 “Hello” 並沒有在 call 之前實例化,直接傳到 call_user_func中。
第三種:多個 Parameter 時。
<?php
 class Hello{
  function talk($who,$p)
  {
    echo $who .' talk with '.$p;
  }// end talk()
 }// end Hello()

$User = new Hello();
$func = 'talk';
call_user_func(array($User,$func),'dennis','allan');
?>
更多的資訊請參考 http://www.php.net/call_user_func
eval()
eval 是把 string 轉變成 PHP 代碼來執行。
這裡提到 eval 只是實現了動態調用的功能,如果不是有特別用法,建議不要使用此方法。 PHP 是解釋的語言,使用 eval 會大大降低程式的執行效能,在實際產品環境中,盡量少用或是不用 eval。
<?php
include_once 'User.php';
$User = new User();
$action = isset($_GET['action']) && !empty($_GET['action']) ?
        $_GET['action'] :
         'query';
eval("\$User->".$action."();");
?>

限於篇幅,其它 動態調用 function 的方法,如 magic _call 等等,這裡討論只是其中一小部分功能,希望能拋磚引玉,讓有興趣的朋友去深入研究或來信討論。