ホームページ > バックエンド開発 > PHPチュートリアル > フロントコントローラーパターンの紹介、パート2

フロントコントローラーパターンの紹介、パート2

Lisa Kudrow
リリース: 2025-02-26 09:55:45
オリジナル
815 人が閲覧しました

An Introduction to the Front Controller Pattern, Part 2

コアポイント

  • フロントエンドコントローラーは、アプリケーションの集中プロキシとして機能し、ページコントローラーやRESTリソースなどの事前定義されたハンドラーにコマンドを割り当てます。
  • フロントエンドコントローラーは、コンパクトな構造を維持し、受信リクエストをルートおよびディスパッチすることができ、完全に機能的なRESTFULコントローラーに拡張し、HTTP動詞を解析し、ディスパッチ前のフック前/ポストに適応することもできます。
  • この記事では、リクエスト/応答サイクルを個別に処理しながら、フロントエンドコントローラー、スタンドアロンルーター、およびスケジューラーで動作する小型だがスケーラブルなHTTPフレームワークを展開する方法を示しています。
  • 著者は、典型的なHTTP要求/応答サイクルのデータと動作をシミュレートするクラスを定義し、ルーティングモジュールの構築、スケジューラのセットアップなど、フロントエンドコントローラーをゼロから構築するプロセスも導入しました。
  • フロントエンドコントローラーモードには、集中制御、コードの複製の削減、懸念のモジュール性と分離の改善の利点がありますが、すべてのWebアプリケーションに適していない場合があり、不適切に実装された場合、単一の障害点になる可能性があります。
フロントエンドコントローラーはアプリケーションの集中プロキシのようなものであり、その主な焦点は、ページコントローラー、休憩リソース、または頭に浮かぶ他のものなどの事前定義されたハンドラーにコマンドを静的または動的に割り当てることです。 。少なくとも1つのシンプルなフロントエンドコントローラーを構築することは、その詳細を理解し、実用的な観点からこのアイデアを促進するための非常に便利な体験です。リクエストを発送するために必要なすべてのロジックは、クラスの境界内にパッケージ化されます。フロントエンドコントローラーの最良の側面の1つは、コンパクトな構造、ルートおよびディスパッチの受信要求のみを維持できることです。または、創造性を表示し、HTTP動詞を解析できる完全に機能的なRESTFULコントローラーを実装できることです。フックなど、すべて統一されたAPIの後ろに。ただし、このアプローチは魅力的ですが、単一の責任原則(SRP)とOOP自体の性質に違反し、さまざまなタスクを複数の細かいオブジェクトに積極的に委任します。それで、これは私がSRPの教訓を壊すことを敢えてするもう一つの罪深い魂であることを意味しますか?ある意味では、はい。そのため、スタンドアロンのルーターとスケジューラーを備えたフロントエンドコントローラーと連携できる小型でスケーラブルなHTTPフレームワークを簡単に展開する方法を示すことで、罪を排除したいと思います。さらに、要求/応答サイクル全体は、自然に自然に調整できるいくつかの再利用可能なクラスによって独立して処理されます。多数の完全に食べられたコンポーネントパッケージ化されたHTTPフレームワークが利用可能であることを考えると、これらのクラスがSRPの性質を保持していても、リクエストをゼロからルーティングしてディスパッチするフロントエンドコントローラーを実装することはばかげているようです。ホイールを再発明するために判断されることを避けるために、私のカスタム実装の一部は、Lars Strojnyが書いた巧妙なEphpMVCライブラリに触発されます。

リクエスト/ルーティング/スケジューリング/応答サイクルを分析します

最初に解決する必要があるタスクは、典型的なHTTP要求/応答サイクルのデータと動作をシミュレートする責任のあるいくつかのクラスを定義することです。これは最初のクラスであり、それが実装するインターフェイスです:

<code>class Request {

  public function __construct($uri, $params) { 
    $this->uri = $uri;
    $this->params = $params;
  }

  public function getUri() {
    return $this->uri;
  }

  public function setParam($key, $value) {
    $this->params[$key] = $value;
    return $this;
  }

  public function getParam($key) {
    if (!isset($this->params[$key])) {
      throw new \InvalidArgumentException("The request parameter with key '$key' is invalid."); 
    }
    return $this->params[$key];
  }

  public function getParams() {
    return $this->params;
  }
}</code>
ログイン後にコピー
リクエストクラスは、着信URIとパラメーター配列をカプセル化し、非常にシンプルなHTTP要求をシミュレートします。簡潔にするために、関連する要求に関連付けられたメソッドセットなどの追加データメンバーは意図的に除外されています。クラスに追加したい場合は、続行してください。独立して存在する薄いHTTP要求ラッパーを使用することは良いことですが、典​​型的なHTTP応答をシミュレートするデータと動作の対応する部分と結合することなく役に立たなくなります。この補足コンポーネントを修正して構築しましょう:

<code>class Response {
  public function __construct($version) {
    $this->version = $version;
  }

  public function getVersion() {
    return $this->version;
  }

  public function addHeader($header) {
    $this->headers[] = $header;
    return $this;
  }

  public function addHeaders(array $headers) {
    foreach ($headers as $header) {
      $this->addHeader($header);
    }
    return $this;
  }

  public function getHeaders() {
    return $this->headers;
  }

  public function send() {
    if (!headers_sent()) {
      foreach($this->headers as $header) {
        header("$this->version $header", true);
      }
    } 
  }
}</code>
ログイン後にコピー
応答クラスは、パートナーリクエストよりも間違いなくアクティブです。これは、HTTPヘッダーを自由にスタックできるベースコンテナとして機能し、クライアントに送信できるようにします。これらのクラスは独立して操作を実行するため、フロントエンドコントローラーの次の部分の構築を開始する時が来ました。典型的な実装では、ルーティング/ディスパッチプロセスはほとんど同じアプローチでカプセル化されており、率直に言ってそれほど悪くはありません。ただし、この場合、これらのプロセスを分解して、異なるクラスに委任する方が良いでしょう。このようにして、物事は平等な責任の点でよりバランスが取れます。ルーティングモジュールを実行するクラスのバッチは次のとおりです。

予想されるように、機能的なルーティングメカニズムを実装する際には多くのオプションがあります。少なくとも私の意見では、上記の方法は実用的で直接的です。特定の操作コントローラーへのパスをバインドする個別のルートクラスと、責任が特定のリクエストオブジェクトに関連付けられたURIと一致するかどうかを確認することに責任が限定されている単純なルーターを定義します。最後に問題を解決するには、前のクラスと並んで使用できるクイックスケジューラを設定する必要があります。これは、次のクラスがどのように行うかです:
<code>class Route {

  public function __construct($path, $controllerClass) {
    $this->path = $path;
    $this->controllerClass = $controllerClass;
  }

  public function match(RequestInterface $request) {
    return $this->path === $request->getUri();
  }

  public function createController() {
   return new $this->controllerClass;
  }
}


class Router {
  public function __construct($routes) {
    $this->addRoutes($routes);
  }

  public function addRoute(RouteInterface $route) {
    $this->routes[] = $route;
    return $this;
  }

  public function addRoutes(array $routes) {
    foreach ($routes as $route) {
      $this->addRoute($route);
    }
    return $this;
  }

  public function getRoutes() {
    return $this->routes;
  }

  public function route(RequestInterface $request, ResponseInterface $response) {
    foreach ($this->routes as $route) {
      if ($route->match($request)) {
        return $route;
      }
    }
    $response->addHeader("404 Page Not Found")->send();
    throw new \OutOfRangeException("No route matched the given URI.");
  }
}</code>
ログイン後にコピー

ディスパッチャーをスキャンすると、2つのことがわかります。第一に、それはいかなる状態でもありません。第二に、各操作コントローラーがexecute()メソッドの表面の下で実行されることを暗黙的に想定しています。これは、必要に応じてやや柔軟なパターンにリファクタリングできます(最初に頭に浮かぶのは、ルートクラスの実装を微調整することです)が、簡単にするために、スケジューラを変更せずに保ちます。これまでのところ、以前のすべてのクラスを組み合わせることができるフロントエンドコントローラーをどのように配置するか疑問に思うかもしれません。心配しないでください、次はそうです!
<code>class Dispatcher {

  public function dispatch($route, $request, $response)
    $controller = $route->createController();
    $controller->execute($request, $response);
  }
}</code>
ログイン後にコピー

(スペースの制限により、後続のコンテンツは切り捨てられます。残りのコンテンツを提供してください。擬似オリジナルを完了し続けます。)

以上がフロントコントローラーパターンの紹介、パート2の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート