2011-08-06 47 views
1

我正在使用HMVC設計模式編寫我自己的PHP框架作爲學習練習。它所有的工作:),但我看過很多次,這是一個壞習慣,是指靜態類在PHP代碼,而這正是我在自動加載功能正在做:在特定文件夾中自動加載模型類的最佳方法HMVC

function __autoload($className) { 
    $path = SERVER_ROOT . DS . 'applications' . DS . Dispatcher::getApplicationName() . DS . 'models' . DS . 'class.' . strtolower($className) . '.php'; 

    if (file_exists($path)) { 
     require_once($path); 
    } else { 
     throw new Exception('Can\'t find a model at "' . $path . '".'); 
    } 
} 

正如你可以看到我使用靜態調用Dispatcher::getApplicationName()得到當前應用程序,根據許多人的說法,這是不好的,因爲它引入了依賴關係。我還可以使用debug_backtrace()來獲取applicationName,因爲啓動模型的類包含ApplicationName作爲屬性。這是更好的,還是有其他的選擇,我沒有想到?

謝謝!

編輯:忘記提及上述代碼還有另一個問題:由於我使用HMVC設計模式(因此控制器被稱爲內部控制器),因此控制器的應用程序並不總是與調度程序的應用程序相同。這隻能使用debug_backtrace來修復。

編輯:而不是Dispatcher::getApplicationName()我現在使用Request::getCurrentApplicationName()。現在它再次工作,因爲我的請求類保存所有應用程序。這是更好的,還是有更好的方法?

<?php 

class Request { 
    private static $_controllers = array(); 
    private static $_applicationsNames = array(); 

    public static function _getCurrentApplicationName() { 
     return end(self::$_applicationsNames); 
    } 

    public static function _load($applicationName, $controllerName, $methodName) { 
     // Add the application the the array (for autoloading). 
     self::$_applicationsNames[] = $applicationName; 

     // Check if the controller has already been instantiated. 
     if (!isset(self::$_controllers[$applicationName . DS . $controllerName])) { 
      require_once(APPLICATIONS_ROOT . DS . $applicationName . DS . 'controllers' . DS . 'class.' . $controllerName . '.php'); 
      self::$_controllers[$applicationName . DS . $controllerName] = new $controllerName($applicationName); 
     } 

     // Get the user arguments. 
     $arguments = array_slice(func_get_args(), 3); 

     // Call the method. 
     $result = call_user_func_array(array(self::$_controllers[$applicationName . DS . $controllerName], $methodName), $arguments); 

     // Remove the last value from the applications array. 
     array_pop(self::$_applicationsNames); 
    } 
} 

回答

2

難道你不能在啓動過程中設置autoload類的靜態成員包含所有必要的信息嗎?

debug_backtrace()不能成爲可靠​​的信息來源。如果有人想使用自己的自動加載器,但是沒有其中一個起始層,您的庫文件怎麼辦?這有可能嗎?

類/函數使用的所有數據都應該放在該類中或作爲該函數的參數。因爲自動加載器可以是任何回調,所以你可以這樣做:

class FrameworkAutoloader 
{ 
    public $appName; 
    public $path; 

    public function setAppName($name) { $this->appName = $name; } 
    public function setPath($path) { $this->path= $path; } 


    function __autoload($className) { 
     $path = $this->path. DS . 'applications' . DS . $this->appName . DS . 'models' . DS . 'class.' . strtolower($className) . '.php'; 

     if (file_exists($path)) { 
      require_once($path); 
     } else { 
      throw new Exception('Can\'t find a model at "' . $path . '".'); 
     } 
    } 
} 

$autoloader = new FrameworkAutoloader(); 
$autoloader->setAppName('asd'); //you can also apply those within constructor, but leave setters 
$autoloader->setPath('asd'); 
spl_autoload_register(array($autoloader, '__autoload')); 

就是這樣。您將能夠動態設置路徑和應用程序名 - 只需通過使用setter更改對象的變量即可。

爲什麼我們應該這樣做?在這個代碼中沒有「魔法」四處走動。您可以使用PHPDOC編寫文檔給每個函數,用戶將知道所有參數來自哪裏。另一個優點是,我可以在任何地方使用此代碼,我不需要知道該類使用Dispatcher :: getApplicationName()。

+0

這意味着我必須更改我的Request類中每個請求的值。這真的比我現在在開始文章中編輯的代碼好嗎? – Frog

+0

我相信這可以通過爲每個應用程序創建單獨的自動加載器來解決。創建註冊機制,它將調用類似MyApplication :: install()的東西。這樣的解決方案將爲您的代碼提供更多的模塊化。 這樣做的另一個好處是可以從不同的應用程序同時加載類(儘管它帶來了一些性能問題,因此您需要決定哪一個更重要)。例如。 PollApp在poll的第一個實例中加載PollTextModel,然後NewsApp加載一些類,最後PollApp加載PollDbModel作爲它的第二個實例。 –

+0

感謝您的回答。這正是我幾個小時前想到的。由於我使用HMVC模式,每個控制器都通過我的'Request'類來實例化。所以我添加一個我的控制器作爲自動加載器的方法,並在請求完成時將其刪除。這工作得很好。謝謝你的幫助! – Frog

0

我會考慮在任何文件中設置一個APPLICATION_ROOT定義來引導應用程序。這將是一件非常有用的事情,不僅在__autoload中有效。

+0

我不能那樣做,因爲'APPLICATION_ROOT'的定義在我的Request類中的每個請求上都有變化。應用程序可以從不同的應用程序加載控制器,然後該應用程序不再正確。你能想到另一種方式嗎? – Frog

相關問題