Jas*_*vis 6 php regex model-view-controller performance uri
我是MVC的新手,所以这是我的第一次尝试,我相信你们可以给我改进,感谢任何提示或帮助!
下面是我为我的个人框架设计的路由器/调度程序系统,这是我第一次尝试使用MVC模式.
第一个代码块只是我的.htaccess文件,它通过我的index.php文件路由所有请求.
第二个代码块是我的"路由"数组,它将告诉Router对象,调用哪个类和方法以及任何ID或分页号(如果存在).
第三块代码是路由器类.
第四块就是运行这个类
因此,路由器类必须使用正则表达式来匹配URI与路由映射中的路由,理论上,这听起来像是一个包含正则表达式必须运行的50多个路由的列表时的糟糕性能,我应该这样做这不一样吗?我使用正则表达式的主要原因是匹配路由中存在的页码和ID号.
另外请不要只是告诉我使用框架,我这样做是为了更好地学习它,我这样学习得更好,只是不喜欢现在使用现有的框架,我研究了所有主要框架和一些不太常见的框架.已有的想法.
1)所以主要问题,做什么只是不正确?
2)有没有更好的方法来检测URI中的内容,而不是像我一样在数组上使用正则表达式,在高流量网站上考虑它?
3)由于所有内容都通过index.php文件进行路由,我将如何处理AJAX请求?
对不起,如果这令人困惑,我自己有点困惑!
.htaccess文件
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?uri=$1 [NC,L,QSA]
Run Code Online (Sandbox Code Playgroud)
地图数组()
/**
* Map URI to class/method and ID and Page numbers
* Must be an array
*/
$uri_route_map = array(
//forums
'forums/' => array(
'controller' => 'forums',
'method' => 'index',
'id_number' => '',
'page_number' => ''),
'forums/viewforum/(?<id_number>\d+)' => array(
'controller' => 'forums',
'method' => 'viewforum',
'id_number' => isset($id_number),
'page_number' => ''),
'forums/viewthread/(?<id_number>\d+)' => array(
'controller' => 'forums',
'method' => 'viewthread',
'id_number' => isset($id_number),
'page_number' => ''),
'forums/viewthread/(?<id_number>\d+)/page-(?<page_number>\d+)' => array(
'controller' => 'forums',
'method' => 'viewthread',
'id_number' => isset($id_number),
'page_number' => isset($page_number)),
// user routes
// account routes
// blog routes
// mail routes
// various other routes
);
Run Code Online (Sandbox Code Playgroud)
读取和匹配上面的Map数组的路由器类
/**
* Run URI against our Map array to get class/method/id-page numbers
*/
class Router
{
private $_controller = '';
private $_method = '';
public $page_number = '';
public $id_number = '';
public function __construct($uri, array $uri_route_map)
{
foreach ($uri_route_map as $rUri => $rRoute)
{
if (preg_match("#^{$rUri}$#Ui", $uri, $uri_digits))
{
//if page number and ID number in uri then set it locally
$this->page_number = (isset($uri_digits['page_number']) ? $uri_digits['page_number'] : null);
$this->id_number = (isset($uri_digits['id_number']) ? $uri_digits['id_number'] : null);
$this->_controller = $rRoute['controller'];
$this->_method = $rRoute['method'];
// just for debug and testing while working on it / will be removed from final code
echo '<hr> $page_number = ' . $this->page_number . '<br><br>';
echo '<hr> $id_number = ' . $this->id_number . '<br><br>';
echo '<hr> $controller = ' . $this->_controller . '<br><br>';
echo '<hr> $method = ' . $this->_method . '<br><br>';
break;
}else{
$this->page_number = '';
$this->id_number = '';
$this->_controller = '404';
$this->_method = '404';
}
}
}
public function getController()
{
return $this->_controller;
}
public function getMethod()
{
return $this->_method;
}
public function getPageNumber()
{
return $this->page_number;
}
public function getIDNumber()
{
return $this->id_number;
}
/**
* Call our class and method from values in the URI
*/
public function dispatch()
{
if (file_exists('controller' . $this->_controller . '.php'))
{
include ('controller' . $this->_controller . '.php');
$controllerName = 'Controller' . $this->_controller;
$controller = new $controllerName($this->getIDNumber(),$this->getPageNumber());
$method = $this->_method;
if (method_exists($this->_controller, $this->_method))
{
return $controller->$method();
} else {
// method does not exist
}
} else {
// Controller does not exist
}
}
}
Run Code Online (Sandbox Code Playgroud)
运行
/**
* Testing the class
*/
$uri = isset($_GET['uri']) ? $_GET['uri'] : null;
$router = new Router($uri, $uri_route_map);
$router->dispatch();
?>
Run Code Online (Sandbox Code Playgroud)
1)在我看来还不错。不过代码看起来有点乱。
2)是的,有更好的方法。您执行正则表达式是因为您想要匹配 URL 中您不知道的部分。为什么不看看$parts = explode("/", $uri)是否可以找到您要查找的页面呢?您需要定义每个页面需要多少个参数,否则您将不知道是选择forumswith 参数array("viewform", 123)还是forums/viewforumwith 参数array(123)。
explode感觉负载比正则表达式更好。它还增加了改进错误处理的好处。如果传递给的参数viewforum不是数字怎么办?当然你可以做得更好"404";)
3)创建一个单独的ajax处理程序。无论如何,Ajax 都是隐藏的,因此您无需费心提供语义 URL。
例子:
function find_route($parts) {
foreach ($uri_route_map as $route => $route_data) {
$route_check = implode("/", array_slice($parts, 0, count($parts) - $route_data['num_arguments']));
if ($route_check === $route) {
return $route_data;
}
}
throw new Exception("404?");
}
$uri = "forum/viewforum/522";
$parts = explode("/", $uri);
$route = find_route($parts);
$arguments = array_slice($parts, count($parts) - $route['num_arguments']);
$controller = $rRoute['controller'];
$method = $rRoute['method'];
$controller_instance = new $controller();
call_user_func_array(array($controller_instance, $method), $arguments);
Run Code Online (Sandbox Code Playgroud)
(未经测试)
插件
由于 $uri_route_map,您无法“动态”注册更多插件或页面或“路由”。我会添加一个函数来动态添加更多路由到Router.
此外,您可以考虑一些自动发现方案,例如,将检查文件夹中plugins/是否有名为“manifest.php”的文件的文件夹,当调用该文件时,将有选择地向路由器添加更多路由。