2009-09-04 30 views
1

我有一個「最佳實踐」問題。我正在PHP中開發一個OO MVC框架,並且大多數類很容易交互 - 它們在代碼中被直接聲明並被使用。例如:OOP PHP - 動態構建/運行對象和函數名稱

// In class 'getDetails' 
$db = new mysqli(.....); 
$db->query(.....); 

但是,有些時候類和函數名是動態構建的。實際的類文件都被創建並位於框架的某個位置,但它們並非全部被直接聲明和使用。直到運行時,框架才知道完成請求需要什麼類;所以類和函數名稱通常會創建並存儲在變量中。在最簡單的情況下,變量用於創建對象並運行一個函數。例如:

$request = 'blog'; 
$action = 'view'; 
$class = new $request(); // Creates an blog object 
$class->$action(); // Runs the blog function view 

然而,試圖用變量運行靜態函數時,我已經遇到的情況(here是堆棧溢出的問題和答案),其中的變量不能在文字使用
使用($ request :: $ action()給出解析錯誤)。我已經在PHP手冊中看到用於交互/使用類,函數和對象的函數,但之前沒有處理它們。

我的問題是什麼是最好的方式來處理和運行類和函數的名稱是在飛行中創建的類和函數?

+0

您可能會閱讀KISS原則(http://en.wikipedia.org/wiki/KISS_principle)。使用Zend,CakePHP,CodeIgniter,Symphony等 – inakiabt 2009-09-04 20:15:37

+0

我明白KISS,但即使Zend,CakePHP,CodeIgniter等也面臨同樣的問題。他們剛剛解決並從用戶那裏提取。 – 2009-09-04 21:23:25

回答

4

你提到的這兩種方法都是好的,但有一定的侷限性:

使用正規表示法:

$request = 'blog'; 
$action = 'view'; 
$class = new $request(); // Creates an blog object 
$class->$action(); // Runs the blog function view 

使用用於實例化類的符號要求您事先知道每個類/方法接受的參數。所以你不能設計一個可以接受任意參數的factory pattern

使用call_user_func_array()允許您使用任意參數。

$request = 'blog'; 
$action = 'view'; 
$params = array(
    $_GET['category'], 
    $_GET['limit'] 
); 
call_user_func_array(array($request, $action), $params); 

所以上面的代碼等同於字面:

blog::view($_GET['category'], $_GET['limit']); 

基本上,call_user_func_array()變平數組$參數,可以在它傳遞的每個值作爲參數傳遞給該方法博客::視圖( )。

爲了做同樣的動態/對象方法調用:

call_user_func_array(array(new $request, $action), $params); 

然而,這並不與創建的任意類的一個實例,並將其傳遞的參數的任意數量的解決問題。要做到這一點,你可以使用ReflectionClass

實施例:

$request = 'blog'; 
$action = 'view'; 
$configs = array('something', 'something else'); 
$params = array(
    $_GET['category'], 
    $_GET['limit'] 
); 
$instance = call_user_func_array(
    array(new ReflectionClass($request), 'newInstance'), 
    $configs 
); 
$return = call_user_func_array(array($instance, $action), $params); 

這將等效於:

$configs = array('something', 'something else'); 
$params = array(
    $_GET['category'], 
    $_GET['limit'] 
); 
$blog = new blog($configs[0], $configs[1]); 
$blog->view($_GET['category'], $_GET['limit']); 

有了這些工具可以動態實例化任意對象和傳遞的參數的任意數量的其__constructor()以及任何方法。

如果您的功能最好,請使用call_user_func_array()和ReflectionClass()。 如果您在性能方面表現最好,請不要擔心。良好的設計和功能可以提高性能。

0

如果我正確理解你的問題,那麼我會用eval這個。您也可以爲靜態函數執行此操作。例如,以下是幾年前我創建的網站的一些代碼。

function StaticObjectPrint($mysql,$template, $objecttype, $debug=0) { 
    foreach(eval("return $objecttype::ReturnStaticVariablesForPrinting(\$mysql);") as $key => $value) { 
     global $$key; 
     $$key = $value; 
    } 
    if($debug==1) 
     print_r ($GLOBALS); 

    return ParsePlainTextFile($template,1); 
} 

在這種情況下,有幾個不同類的對象,但它們都有一個ReturnStaticVariablesForPrinting函數。根據用戶點擊哪種類型的對象,它將返回關於該對象的一些靜態信息,而不必實例化每個對象(並捆綁一堆內存)。這對於生成對象屬性列表非常有用。 (我知道這違反了一些面向對象的原則,但它是速度必要)