問題描述
所以我開始更深入地研究 MVC(真正的 MVC,而不是框架 MVC),并且我正在嘗試開發一個小型框架.我通過閱讀其他框架(例如 Symphony 和 Zend)來工作,了解它們的工作方式,并嘗試自己實現.
So I've started studying MVC (real MVC, not framework MVC) a bit more in-depth, and I'm attempting to develop a small framework. I'm working by reading other frameworks such as Symphony and Zend, seeing how they do their job, and attempt to implement it myself.
我卡住的地方是 URL 路由系統:
The place where I got stuck was the URL routing system:
<?php
namespace ApplicationCommon;
class RouteBuilder {
public function create($name, $parameters) {
$route = new Route($name);
$route->resource = array_keys($parameters)[0];
$route->defaults = $parameters["defaults"];
$notation = $parameters["notation"];
$notation = preg_replace("/[(.*)]/", "(:?$1)?", $notation);
foreach ($parameters["conditions"] as $param => $condition) {
$notation = str_replace($param, $condition, $notation);
}
$notation = preg_replace("/:([a-z]+)/i", "(?P<$1>[^/.,;?
]+)", $notation);
//@TODO: Continue pattern replacement!!
}
}
/* How a single entry looks like
* "main": {
"notation": "/:action",
"defaults": {
"resource" : "Authentication",
},
"conditions": {
":action" : "(login)|(register)"
}
},
*/
我就是無法將頭正確地纏繞在它上面.這里的應用工作流程是什么?
I just can't get my head wrapped around it properly. What is the application workflow from here?
pattern 生成了,大概是一個Route
對象保存在Request
對象下什么的,然后呢?它是如何工作的?
The pattern is generated, probably a Route
object to be kept under the Request
object or something, then what? How does it work?
P.S. 在這里尋找一個真實的、解釋清楚的答案.我真的很想了解這個主題.如果有人花時間寫一個真正詳盡的答案,我將不勝感激.
P.S. Looking for a real, well explained answer here. I really want to understand the subject. I would appreciate if someone took the time to write a real elaborate answer.
推薦答案
一個 MVC Router
類(它是更廣泛的前端控制器的一部分)分解 HTTP 請求的URL——特別是路徑組件(可能還有查詢字符串).
An MVC Router
class (which is part of a broader Front Controller) breaks down an HTTP request's URL--specifically, the path component (and potentially the query string).
Router
嘗試將路徑組件的前一個或兩個部分與相應的路由組合(Controller
/Action [method],或者只是一個執行默認操作(方法)的Controller
.
The Router
attempts to match the first one, or two, parts of the path component to a corresponding route combination (Controller
/ Action [method], or just a Controller
that executes a default action (method).
一個動作或命令,只是一個特定Controller
的方法.
An action, or command, is simply a method off of a specific Controller
.
通常有一個抽象控制器
和許多Controller
的子節點,每個網頁一個(一般來說).
There is usually an abstract Controller
and many children of Controller
, one for each webpage (generally speaking).
有些人可能會說 Router
還會將參數傳遞給所需的 Controller
方法,如果 URL 中存在任何參數.
Some might say that the Router
also passes arguments to the desired Controller
's method, if any are present in the URL.
注意:遵循單一職責原則的面向對象編程純粹主義者可能會爭辯說,路由 URL 的組件和調度code>Controller 類是兩個獨立的職責.在這種情況下,Dispatcher
類實際上會實例化 Controller
并將其方法之一傳遞給從客戶端 HTTP 請求派生的任何參數.
Note: Object-oriented programming purists, following the Single Responsibility Principle, might argue that routing components of a URL and dispatching a Controller
class are two separate responsibilities. In that case, a Dispatcher
class would actually instantiate the Controller
and pass one of its methods any arguments derived from the client HTTP request.
示例 1:Controller
,但沒有操作或參數.
Example 1: Controller
, but no action or arguments.
http://localhost/contact
在 GET 請求中,這可能會顯示一個表單.
http://localhost/contact
On a GET request, this might display a form.
控制器 = 合約
Action = 默認(通常是 index()
方法)
Action = Default (commonly an index()
method)
======================
======================
示例 2:Controller
和動作,但沒有參數.
Example 2: Controller
and action, but no arguments.
http://localhost/contact/send
在 POST 請求中,這可能會啟動服務器端驗證并嘗試發送消息.
http://localhost/contact/send
On a POST request, this might kick of server-side validation and attempt to send a message.
控制器 = 合約
操作 = 發送
======================
======================
示例 3:Controller
、動作和參數.
Example 3: Controller
, action, and arguments.
http://localhost/contact/send/sync
在 POST 請求中,這可能會啟動服務器端驗證并嘗試發送消息.但是,在這種情況下,JavaScript 可能未處于活動狀態.因此,為了支持優雅降級,您可以告訴 ContactController
使用支持屏幕重繪的 View
并使用 Content-Type: text/的 HTTP 標頭響應html
,而不是 Content-Type: application/json
.sync
將作為參數傳遞給 ContactConroller::send()
.請注意,我的 sync
示例完全是隨意編造的,但我認為它符合要求!
http://localhost/contact/send/sync
On a POST request, this might kick of server-side validation and attempt to send a message. However, in this case, maybe JavaScript is not active. Thus, to support graceful degradation, you can tell the ContactController
to use a View
that supports screen redraw and responds with an HTTP header of Content-Type: text/html
, instead of Content-Type: application/json
. sync
would be passed as an argument to ContactConroller::send()
. Note, my sync
example was totally arbitrary and made up, but I thought it fit the bill!
控制器 = 合約
操作 = 發送
Arguments = [sync]
//是的,在數組中傳遞參數!
Arguments = [sync]
// Yes, pass arguments in an array!
Router
類實例化請求的具體子Controller
,從控制器實例調用請求的方法,并將其參數(如果有)傳遞給控制器??方法.
A Router
class instantiates the requested, concrete child Controller
, calls the requested method from the controller instance, and passes the controller method its arguments (if any).
1) 您的 Router
類應該首先檢查是否有一個具體的 Controller
可以實例化(使用找到的名稱在 URL 中,加上控制器"一詞).如果找到控制器,測試請求的方法是否存在(行動).
1) Your Router
class should first check to see if there is a concrete Controller
that it can instantiate (using the name as found in the URL, plus the word "Controller"). If the controller is found, test for the presence of the requested method (action).
2) 如果 Router
在運行時找不到并加載必要的 PHP(使用 autoloader 被建議)實例化一個具體的 Controller
子項,然后它應該檢查一個數組(通常在另一個類名 Route
) 以查看請求的 URL 使用正則表達式匹配 中包含的任何元素.Route
類的基本框架如下.
2) If the Router
cannot find and load the necessary PHP at runtime (using an autoloader is advised) to instantiate a concrete Controller
child, it should then check an array (typically found in another class name Route
) to see if the requested URL matches, using regular expressions, any of the elements contained within. A basic skeleton of a Route
class follows.
注意:.*?
= 零個或多個任意字符,非捕獲.
Note: .*?
= Zero, or more, of any character, non-capturing.
class Route
{
private $routes = [
['url' => 'nieuws/economie/.*?', // regular expression.
'controller' => 'news',
'action' => 'economie'],
['url' => 'weerbericht/locatie/.*?', // regular expression.
'controller' => 'weather',
'action' => 'location']
];
public function __contstruct()
{
}
public function getRoutes()
{
return $this->routes;
}
}
為什么要使用正則表達式?一個不太可能在 URL 中的第二個正斜杠之后完成數據的可靠匹配.
Why use a regular expression? One is not likely to get reliable matching accomplished for data after the second forward slash in the URL.
/controller/method/param1/param2/...
,其中 param[x] 可以是任何東西!
/controller/method/param1/param2/...
, where param[x] could be anything!
警告:當目標數據包含模式分隔符(在本例中為正斜杠/")時,最好更改默認的正則表達式模式分隔符 ('/').幾乎所有非有效的 URL 字符將是一個不錯的選擇.
Warning: It is good practice change the default regular expression pattern delimiter ('/') when targeting data contains the pattern delimiter (in this case, forward slashes '/'. Almost any non-valid URL character would be a great choice.
Router
類的一個方法將遍歷 Route::routes
數組以查看目標 URL 和 之間是否存在正則表達式匹配string
value 與第二級 url
索引相關聯.如果找到匹配項,Router
然后知道要實例化哪個具體的 Controller
以及要調用的后續方法.參數將根據需要傳遞給方法.
A method of the Router
class will iterate over the Route::routes
array to see if there is a regular expression match between the target URL and the string
value associated with a 2nd level url
index. If a match is found, the Router
then knows which concrete Controller
to instantiate and the subsequent method to call. Arguments will be passed to the method as necessary.
始終警惕邊緣情況,例如表示以下內容的 URL.
Always be wary of edge cases, such as URLs representing the following.
`/` // Should take you to the home page / HomeController by default
`''` // Should take you to the home page / HomeController by default
`/gibberish&^&*^&*%#&(*$%&*#` // Reject
這篇關于MVC 路由是如何工作的?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!