使用类似 .NET 控制器的 PHP MVC





5.00/5 (14投票s)
一个模仿 C# 控制器的 PHP MVC 模型。
引言
我主要使用 ASP.NET 工作,因此爱上了其 MVC 模型的简洁性。只需单击“新建控制器”,然后确认创建视图,您就会获得一段控制器代码,它再简单不过了。
但互联网主要由 PHP/MySQL 构建,如果您要为街角的面包店构建一个网站,包含 Zend 或其他大型 MVC 框架可能有点过头了。我想用 PHP 创建一个简单的 MVC 模型,其中控制器类可以像 .NET 变体一样简单。
在 .NET 中,您可以选择多个模板引擎。在我向您展示的模型中,您可以轻松插入任何您喜欢的模板引擎。我选择了 Smarty。 https://smarty.php.ac.cn/
我并没有声称这是独一无二的,有很多很棒的框架可以做同样的事情。 比如 CodeIgniter。 但我认为看看你如何自己动手做会很有趣。
代码
首先要做的是。 因为我们想要一个 MVC 模型,所以我们需要所有请求都通过一个单一的来源进行路由。 这是通过更改 * .htaccess * 文件完成的。
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(\.css|\.js|\.jpg|\.jpeg|\.png|\.gif|\.flv|\.swf)$
RewriteRule ^.*$ index.php
注意例外列表。 你不会想通过控制器路由 CSS。 虽然这可能是将你的 * .sass * 或 * .less * 文件转换为 * .css * 的地方。 对于缩小的 JavaScript 文件或优化的图像也是如此。
引导
我设置了一个 ini 文件。 其中包含一些有价值的设置。 * index.php * 要做的第一件事是解析这个文件。
[settings]
controller_path="controllers/"
view_path="views/"
baseURL="/subdir"
baseUrl
可以为空。 如果它安装在站点的根目录中
*index.php* 然后将包含 smarty 并做一些基本的事情。 然后做解析传入请求 URL 的最重要的部分。
如果 URL 是 home,那么 *homeController.php* 应该包含该控制器。 因此,如果 URL 是 *products/details/10*,则应加载 *productsController.php*。
<?php
require_once('libs/Smarty.class.php');
$config = parse_ini_file("config.ini", TRUE);
if (isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD'])) {
//This will hold the request data. If there is any.
$requestData = '';
//The method
$method = $_SERVER['REQUEST_METHOD'];
if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) {
//There is some data in the request. We would like to have this.
$httpContent = fopen('php://input', 'r');
while ($data = fread($httpContent, 1024)) {
$requestData .= $data;
}
fclose($httpContent);
}
//If we are installed in a subdirectory, we'd like to analyse the part after this directory
$urlString = substr($_SERVER['REQUEST_URI'], strlen($config['settings']['baseURL']));
//Split the url in pieces
$urlParts = explode('/', $urlString);
if (isset($urlParts[0]) && $urlParts[0] == '') {
array_shift($urlParts);
}
if (!isset($urlParts[0]) || $urlParts[0] == '') {
//If the url does not contain more then / we're going to start the default controller. Which is home
$mainViewPath="home/";
$currentController = "HomeController";
$controllerFile = "homeController.php";
}
else {
//There is a directive after the / so that is going to be our controller
$mainViewPath=strtolower($urlParts[0]);
$currentController = ucfirst($urlParts[0]) . "Controller";
$controllerFile = $urlParts[0] . "Controller.php";
//This will make the 'action' part of the url the first directive
array_shift($urlParts);
}
}
else {
header($_SERVER["SERVER_PROTOCOL"] . " 400 Bad request");
}
?>
抽象类控制器
因此,我们现在知道我们想启动哪个控制器类。 如果有人给我们请求 URL/products,我们想要加载 *productsContoller.php* 并创建 ProductsController 的一个实例。
但首先我们需要专注于创建一个抽象类控制器。 为了让我们的控制器具有如此简单的结构,我们需要一个将完成所有繁重工作的超类。
所有控制器都将从此类继承。 控制器类需要做一些事情。 它需要查看请求 URL 剩下的部分,并确定应该启动控制器中的哪个操作。 因此,如果我们得到 /products,则没有定义操作,我们将启动 index 操作。 如果我们得到 /products/details,我们将启动 details 操作。
控制器类需要做的第二件事是创建 viewBag。 这是一个“数据包”,实现控制器可以将数据添加到其中。 但是除此之外,我也想假设 POST 数据是 JSON,并且所有 POST 数据在启动控制器操作之前都会添加到 viewBag。 这将允许从 JavaScript 设置模板变量。 (但这可能更适合下次)。
他做的第三件事是确定 *view.html* 文件。
控制器类做的最后一件事是实现 View() 函数,它将 viewBag 应用于模板。
构造函数
//@contructor
//@param controllerName, The name of the controller. E.g. ME
//@param urlParts The urlParts that are left.
// If the original request was products,details,10 then this wil hold details,10
//@param data de JSON data, The request data.
public function __construct($controllerName, $urlParts, $data)
{
$this->fullActionPath=implode("/", $urlParts);
$this->method=$_SERVER['REQUEST_METHOD'];
//We are assuming the data to be a JSON string. In a final version this should have some error handling
if($data=='') {
$data='{}';
}
$this->viewBag=json_decode($data);
//The action is the first part
$action=$urlParts[0];
if (count($urlParts) > 1 && $urlParts[1] != '') {
//Now we need to find the identifiers
array_shift($urlParts);
foreach ($urlParts as $uid) {
if ($uid != '') {
$this->uid[] = $uid;
}
}
}
if(!isset($action) || $action=='') {
//If there is no action, we'll start the default action.
$action="index";
}
//The view html
$this->viewHtml=strtolower($action) . ".html";
try {
//call_user_func gives a fatal error, which we cannot catch.
//So we cannot handle asking for a unknown action
//This is why we'll use the ReflectionClass's getMethod which will throw an exception
$reflector = new ReflectionClass($this);
$method=$reflector->getMethod($action);
//If all works. We'll start the action.
call_user_func($controllerName . "::" . $action, $this->uid);
}
catch(Exception $exc) {
//If the view doesn't exists, we'll start the default view.
//In a final version this should start the ViewUnknown action.
call_user_func($controllerName . "::index");
}
}
View 函数
//@method View
//@description Combines the view with the viewBag data.
public function View()
{
//Detertime the full path to the view file
$viewPath=$GLOBALS['config']['settings']['view_path'] . $this->viewHtml;
if (file_exists($viewPath)) {
//If the file exists use the smart engine
//This would be the place to use some other engine like Mustache
$this->smarty = new Smarty();
foreach($this->viewBag as $key => $value) {
$this->smarty->assign($key, $value);
}
$this->smarty->display($viewPath);
}
else {
header('HTTP/1.0 404 Not Found');
echo "404 Not Found";
echo "The page that you have requested could not be found.";
}
}
我们需要将 require_once('classes/Controller.php')
添加到我们的 *index.php*。
主页视图和控制器
现在我们准备创建视图和控制器,但首先我会提醒您具有 controller_path
和 view_path
的 * .ini * 文件。 这决定了下面的文件结构
- baseURL
- 类
- Controller.php
- Smarty.class.php
- 控制器
- homeController.php
- 视图
- 主页
- index.html
- .htaccess
- config.ini
- index.php
HomeController
<?php
/*
@class HomeControlelr
@extends Controller
@description Dit is de controller for home
*/
class HomeController extends Controller
{
//@method index De index action
public function index()
{
//Lets set some variable to test the template
$this->viewBag->hellomessage="Hello world!";
return $this->View();
}
}
?>
home/index.html
<html>
<head>
<title>Index</title>
</head>
<body>
<h1>{$hellomessage}</h1>
</body>
</html>
基本上就是这样。
结论
虽然这需要更多的细节才能在真实的场景中使用,但我相信它表明你可以使用 PHP 创建一个简单的 MVC。 对于小型网站,这几乎就足够了。 在 zip 文件中,我已经将示例详细化了一些。 它包含一个面包店网上商店的详细示例。 它也适用于共享模板,以便我们可以将 html 包装在我们的视图周围。 不过,MVC 最重要的部分之一缺失了。 我将在下一篇文章中介绍这一点。
这是我的第一篇文章,我并不是一个核心 PHP 程序员,欢迎任何评论。