2011-08-06 7 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()を使用して取得することができます。これは依存関係を導入するため、多くの人によると悪いことです。モデルを開始するクラスにはプロパティとしてApplicationNameが含まれているため、debug_backtrace()を使用して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を使用してオブジェクトの変数を変更するだけで、パスとappnameを動的に設定することができます。

なぜこのようにする必要がありますか?このコードには、「魔法」はありません。すべての関数にPHPDOCを使用してドキュメントを書くことができ、ユーザはすべてのパラメータがどこから来たのかを知ることができます。もう1つの利点は、クラスがDispatcher :: getApplicationName()を使用しているので、どこでもこのコードを使用できることです。知る必要はありません。

+0

つまり、リクエストクラスのすべてのリクエストの値を変更する必要があります。これは私の最初の投稿で編集したコードよりも本当に優れていますか? – Frog

+0

これは、アプリケーションごとに別々のオートローダーを作成することで解決できると思います。 MyApplication :: install()のようなものを呼び出す登録メカニズムを作成します。このようなソリューションは、コードにさらにモジュール性を提供します。 別の利点は、異なるアプリケーションからクラスを同時にロードする可能性があることです(パフォーマンス上の問題が発生するため、どちらが重要かを判断する必要があります)。例えば。 PollAppはポーリングの最初のインスタンスでPollTextModelをロードし、NewsAppはいくつかのクラスをロードし、最後にPollAppはその2番目のインスタンスに対してPollDbModelをロードします。 –

+0

あなたの答えをありがとう。それはまさに私が数時間前に思ったことです。 HMVCパターンを使用するので、すべてのコントローラは私の 'Request'クラスを通してインスタンス化されます。そこで、私のコントローラのメソッドをオートローダーとして追加し、リクエストが完了したらそれを削除します。これは本当にうまくいく。ご協力いただきありがとうございます! – Frog

0

APPLICATION_ROOTの定義をアプリケーションのブートストラップファイルに設定することを検討します。それは__autoloadだけでなく、いつでも利用できる便利なものになります。

+0

私の 'Request'クラスのすべてのリクエストに対して' APPLICATION_ROOT'の定義が変更されるため、これを行うことはできません。アプリケーションは、別のアプリケーションからコントローラをロードすることができ、アプリケーションはもう正しくありません。あなたは他の方法を考えることができますか? – Frog

関連する問題