Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/37.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何处理MVC网站的模板?_Php_Model View Controller_View - Fatal编程技术网

Php 如何处理MVC网站的模板?

Php 如何处理MVC网站的模板?,php,model-view-controller,view,Php,Model View Controller,View,我将其标记为PHP,但这只是因为我将使用PHP代码来显示我的问题 我有一些类似于控制器的代码: switch ($page) { case "home": require "views/home.php"; break; case "search": require "views/search.php"; break; } $_SESSION['page'] = sanitize_input($_GET['page

我将其标记为PHP,但这只是因为我将使用PHP代码来显示我的问题

我有一些类似于控制器的代码:

switch ($page)
{
    case "home":
        require "views/home.php";
        break;
    case "search":
        require "views/search.php";
        break;
}
$_SESSION['page'] = sanitize_input($_GET['page']);
require "templates/main.php";
很明显,有更多的页面,但这应该说明我的问题。这两个页面(以及网站上的所有页面)都有一个通用的页眉、导航和页脚。我应该使用多个require语句吗?我的第一个猜测是:

switch ($page)
{
    case "home":
        require "templates/header.php";
        require "templates/navigation.php";
        require "views/home.php";
        require "templates/footer.php";
        break;
    case "search":
        require "templates/header.php";
        require "templates/navigation.php";
        require "views/search.php";
        require "templates/footer.php";
        break;
}

不知怎的,我的直觉告诉我这是不正确的。

控制器应该为视图设置数据,然后选择要显示的视图。视图应该负责页面的布局,包括共享页面。我喜欢你的第一个样品而不是第二个。

是的,你应该把页眉、页脚等分开

对于您展示的特定示例,这不是更好吗

    require "templates/header.php";
    require "templates/navigation.php";
    require "views/$page.php";
    require "templates/footer.php";

(其中$page是“home”、“search”等)。

如果您使用的是纯PHP页面作为模板,则基本上可以设置一个全局/会话变量来保存所需的页面。您将拥有一个包含页眉和页脚元素的“主模板”php页面,然后调用$page的include。控制器中的类似内容:

switch ($page)
{
    case "home":
        require "views/home.php";
        break;
    case "search":
        require "views/search.php";
        break;
}
$_SESSION['page'] = sanitize_input($_GET['page']);
require "templates/main.php";
然后在main.php模板文件中:

require "templates/header.php";
require "templates/navigation.php";
require "views/{$_SESSION['page']}.php";
require "templates/footer.php";

以下是我如何使用当前项目创建模板的简化版本(如果有任何用途):

class Template {
    var $pagename = 'index';

    function __construct() {
        $this->pagename = basename($_SERVER['SCRIPT_NAME'], '.php');
        register_shutdown_function(array($this, 'do_output'));
    }

    function do_output() {
        $this->header();
        $this->display($this->pagename);
        $this->footer();
    }

    function __call($template, array $params) {
        call_user_func(array($this, 'display'), $template, params);
    }

    function display($template, array $params = null) {
        include "templates/$template.php";
    }
}
其背后的思想是,您可以编写“include'Template.inc';new Template;”,并安排do_output()在脚本末尾自动运行。它遗漏了一些东西,比如用于向模板传递变量的方法

您已经提到,您没有使用PHP,其中有一些PHP ISM:register\u shutdown\u function()确保在对象析构函数之前但在主脚本之后调用模板,并且对$this->header()/footer()的调用是只执行display('header')和display('footer')的神奇函数调用,他们注定要被推翻

当然,像您发布的示例那样使用开关并没有什么错,但您不需要在每个case语句中都使用页眉/页脚。像这样的东西也会做同样的事情:

require "templates/header.php";
require "templates/navigation.php";
switch ($page)
{
    case "home":
        require "views/home.php";
        break;
    case "search":
        require "views/search.php";
        break;
}
require "templates/footer.php";

…或者,如果switch()符合页面设置方式,则可以使用基于文件名的内容(如我上面使用的)替换它。如果您打算通过URL参数进行切换,则切换是最安全的方式。

您在重复代码。这几乎从来都不是个好主意。为了更接近您最初的示例,以下内容肯定更可取:

require "templates/header.php";
require "templates/navigation.php";

switch ($page) {
    case "home":
        require "views/home.php";
        break;
    case "search":
        require "views/search.php";
        break;
}

require "templates/footer.php";

如果不了解更多的体系结构方法,就很难给出更多的建议。例如,建议将控制器的这一部分(它只是准备输出)放在非常中心的位置,并在包含视图模板之前开始输出缓冲。通过这种方式,您可以将输出存储在一个变量中,在返回HTTP响应中的内容之前,您可能需要进一步处理该变量。

我同意tvanfosson的观点,并想解释它与MVC的关系

第二个示例的问题是,控制器暴露于视图的构造方式。在严格意义上,控制器封送视图的输入并将其传递给视图,仅此而已

一种实用的想法是,视图是否会根据应用程序需求或输入本身而改变。例如,如果正在生成的视图是针对JavaScript弹出窗口的,那么它可能(也可能会)使用一组不同的页眉、页脚、CSS、meta等。在第二个示例中,所有这些都是向控制器公开的。在第一个例子中,视图知道如何生成视图——这正是问题所在


为了进一步说明我的示例,假设JavaScript弹出窗口被重新设计为完整的页面视图,或者为AJAX进行重构(或者弹出/页面/AJAX问题由输入决定,例如字段中的隐藏元素)。现在您正在撕裂控制器,因为视图已更改。与其说你违反了MVC,还不如说你一开始就不应该这么做。

如果你的所有文件名都符合你的视图/页面请求,如你的示例所示,那么你只需要一行,没有
开关
语句:

require "templates/header.php";
require "templates/navigation.php";
require 'views/' . $page . '.php'; // <-- one-liner
require "templates/footer.php";
需要“templates/header.php”;
需要“templates/navigation.php”;

需要“视图/”$第页。php';//这并不能回答我的问题,我不认为smart中的两个文件都有相同的页眉/页脚/导航。尤其是因为它公然违背了干燥原则。不一定。ASP.NETMVC提供了母版页,允许分离关注点(这就是我所说的)和保持干燥原则。对php框架了解不够,不知道是否有一个具有类似功能的框架。对我来说,维护SOC比DRY更重要。我有点好奇,当它直接回答OP的问题时,为什么会被否决。如果他不想使用这种格式,可以使用模板引擎或框架。任何其他方式都会导致代码重复。$\此处不应使用会话。我们没有将数据传送到下一个请求。否则你会朝着正确的方向前进。我只是把它作为一个简单的例子。将其存储在某种类型的数据结构中,以便包含的页面可以引用它是很好的。我不喜欢带上常规的“全局”变量。耸肩