2

「ルーティング」という用語を正しく使用しているかどうかはわかりませんが、状況は次のとおりです。

次のように、アプリケーションのURLを「処理」するファイルを作成しました.htaccess(私の用語が正しいかどうかはわかりません):

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f

RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]

今私はこれを持っています:

http://appname/controller/method/parameter
http://appname/$url[0]/$url[1]/$url[2]

私がしたことは次のとおりです。

  1. URLで指定されていない場合に備えて、デフォルトのコントローラーをセットアップします
  2. コントローラーラッパーをセットアップする

私はこのようにそれをやった

$target = new $url[0]()
$controller = new Controller($target)

その問題は、コントローラーのコンストラクターで渡したオブジェクトのメソッドを使用できないことです。

私はこのように解決しました:

class Controller {
  protected $target;
  protected $view;

  public function __construct($target, $view) {
    $this->target = $target;
    $this->view = $view;
  }

  public function __call($method, $arguments) {
    if (method_exists($this->target, $method)) {
        return call_user_func_array(array($this->target, $method), $arguments);
    }
  }
}

これは正常に機能しています。問題は、ルーティングを行ったインデックスで発生します。ここにあります

if(isset($url[2])){
    if(method_exists($controller, $url[1])){
         $controller->$url[1]($url[2])
    }
} else {
    if(method_exists($controller, $url[1])){
         $controller->$url[1]()
    }
}

どこ$controller = new Controller($target)

問題は、メソッドが存在しないことです。メソッドが存在するかどうかを確認せずに直接使用できますが、どうすればこれを解決できますか?

4

3 に答える 3

2

method_existsすでに発見したように、魔法の__callメソッドで処理されている場合は使用できません。ただし、この問題を回避するために、追加のパブリック メソッドをコントローラーに追加できます。

class Controller {
  protected $target;
  protected $view;

  public function __construct($target, $view) {
    $this->target = $target;
    $this->view = $view;
  }

  public function hasMethod($method) {
    return is_callable(array($this->target, $method));
  }

  public function __call($method, $arguments) {
    if (!is_callable(array($this->target, $method))) {
        throw new \BadMethodCallException("Method `$method` is not callable");
    }

    return call_user_func_array(array($this->target, $method), $arguments);
  }
}

そう...

if(isset($url[2])){
    if($controller->hasMethod($url[1])){
         $controller->$url[1]($url[2])
    }
} else {
    if($controller->hasMethod($url[1])){
         $controller->$url[1]()
    }
}

EDIT : public メソッドのみが true を返すように変更method_existsされました。is_callable

于 2012-12-13T16:58:36.183 に答える
1

簡単な答え:あなたは間違っています。もう少し長いもの...

ここでの主な問題は、コントローラーのルーティング メカニズムを押し込もうとしているということです。最新の MVC パターンのコントローラーは、ユーザー入力から情報を取得し、それをモデル レイヤーや現在のビューに適用して状態を変更する役割を果たします。

生の入力データから情報を抽出する責任を負うべきではありません。これは、コードが実際にMVCトライアドに到達する前に使用される何らかの形式のルーティング メカニズムによって行う必要があります。できれば、アプリケーションのブートストラップ/開始段階で。

基本的には次のようなことをします:

$uri = isset( $_GET['url'] ) ? $_GET['url'] : '/';
$request = new Request;
$request->setUrl( $url );

$router = new Router;
$router->route( $request );

$class = $request->getParameter('controller');
$method = $request->getParameter('action');

if ( !class_exists( $class ))
{
    $class  = 'ErrorController';
    $method = 'missingController';
}

if ( !is_callable( [$class, $method] ))
{
    $class  = 'ErrorController';
    $method = 'missingAction';
}

$controller = new $class( /* inject some dependencies */ );
$controller->{$method}( $request );

もちろん、これは単純化されたやや不器用な例です。プロダクション コードにコピー アンド ペーストしないでください。

于 2012-12-26T23:04:27.297 に答える
1

is_callable()の代わりに使用するmethod_exists()と、正しい結果が返されます。

于 2012-12-13T17:01:40.983 に答える