【问题标题】:MVC: Why bother "sending" data to the ViewMVC:为什么要麻烦“发送”数据到视图
【发布时间】:2011-12-17 23:50:23
【问题描述】:

我对 MVC 非常陌生,因此我一直在网上搜索,试图构建自己的框架,以真正了解整个概念的工作原理。

无论如何,几乎所有处理 MVC 的教程似乎总是将需要在视图中显示的数据分配给然后在视图中使用的中间变量。

我的问题是,为什么要费心这额外的步骤?

大多数 MVC 实现最终都包括控制器内的视图...所以如果是这种情况,为什么要浪费时间/内存/cpu 周期来创建中间变量/数组,然后在视图结束时传递给视图最后包含在控制器中。

直接在视图本身中使用控制器变量不是更有意义吗?

这是一个代码示例,希望能阐明我的意思:

class News_Controller 
{

public function main(array $getVars)
{
    $newsModel = new News_Model;

    //get an article
    $article = $newsModel->get_article($getVars['article']);

    //create a new view and pass it our template name
    $view = new View_Model($this->templateName);

    //assign article data to view
    $view->assign('title' , $article['title']);
    $view->assign('content' , $article['content']);
    $view->render();
}

render 函数基本上只是一个包含,将 View 带入 Controller 以在链中显示。如果是这样的话,可以直接在 View 中使用 $article,而不必费心为 View 分配变量。

【问题讨论】:

  • 将值从“控制器”传递到“视图”的方法在 Faux/Web-MVC 框架中是多种多样的。虽然重用本地范围同样可行,但通常会为外观创建值对象或数组,并假设存在视图变量的“收集”过程。
  • 在上面的代码中,如果没有以某种方式传递给视图,您希望视图对象如何访问控制器对象中的变量?此外,似乎您可以简单地将整篇文章传递到您的视图中,而不是一个一个地传递每个文章变量。
  • @dqhendricks,$view->render() 方法基本上只是 'include('view.php')',所以视图包含在控制器中。一旦发生这种情况,Controller 中的变量就会变成 View 文件中的局部变量。从我在网上看到的示例中,视图总是在某些时候被包含到控制器中。是否有另一种方法可以在不包含在控制器中的情况下渲染视图,而控制器又包含在 index.php 文件中...?
  • @Chrys G. 我认为您对 PHP 中变量作用域的工作方式感到困惑。仅仅因为从控制器对象中调用渲染方法并不意味着它继承了它的变量范围。属于视图的方法只能访问视图的变量范围。 php.net/manual/en/language.variables.scope.php

标签: php model-view-controller view controller


【解决方案1】:

您的包含从 render() 方法的变量范围继承所有内容,但 render() 方法不从控制器的变量范围继承任何内容。

class foo {

   public function bar() {
      echo $somevar;
   }
}

$somevar = 'test';
$foo = new foo();
$foo->bar();

此代码将不回显任何内容并警告您 $somevar 尚未定义(如果您的错误报告设置为显示警告)。这是因为方法和函数不继承调用它们的范围。

php.net/manual/en/language.variables.scope.php

php.net/manual/en/language.oop5.visibility.php

【讨论】:

  • 感谢您的示例。我明白你在说什么,但我不知道它是否真的代表了上面例子中发生的事情。在我发布的示例中,变量是在一个函数中声明的,然后在该 SAME 函数中,包含另一个直接引用声明的变量的 php 文件。一旦包含这个文件,它就存在于函数中,因此函数中声明的所有变量都在范围内(我猜你甚至可以说它们是本地的)。
  • @Chrys G. 相信我,确实如此。包含在方法中发生的事实不会影响与变量范围有关的任何事情。如果 `echo $somevar' 包含在 bar() 方法中包含的文件中,它的行为方式完全相同。
  • @Chrys G. 你错了。在您的示例中,变量是在一个完全独立的方法(main)中声明的,而不是包含发生(render)的方法。
  • @Chrys G. 如果包含发生在 main() 方法中而不是在 render() 方法中,那么您将是正确的。
  • 你是对的!谢啦。我终于明白为什么我会被绊倒。我在 index.php 文件中定义的常量在视图文件中工作,所以我认为控制器中声明的变量也是如此。当我再次测试该理论时,它不起作用。对于其他阅读本文的人来说,我在 index.php 文件中定义的常量在整个项目中起作用的原因是因为在 index.php 文件中(通过要求)调用了自动加载器类——其中定义了所有常量。
【解决方案2】:

MVC 是一个非常松散的分类。您正在描述它可能工作的一种方式。您在控制器中使用的变量也可能不打算在您的视图中按原样使用。你可能有某种模板处理器,它从控制器中接收数据,以及一个特别标记的视图模板,然后输出结果。或者,您可能正在视图中调用返回现成标记的函数/方法。

【讨论】:

    【解决方案3】:

    请记住,PHP 会在写入时复制。因此,简单的变量赋值不会对性能造成重大影响。

    如前所述,范围在这里是一个大问题。视图是独立于控制器的实体,无法访问其数据。当然,您可以将控制器的实例传递给视图,但这会在两者之间造成不必要的过于严格的耦合。视图应该能够独立于控制器工作。

    因此,通过将数据显式分配给视图,您可以将两者解耦。因此,您将倾向于编写更好、更简洁的代码。

    其次,将数据分配给视图的过程可能会进行一些数据清理或其他额外工作。例如,在我的框架中,我认为传递给 HTML 视图的所有数据都是不安全的。当数据被传递到视图时(除非明确标记为安全),它通过htmlspecialchars 进行编码。

    最后,您总是可以将对象或数组分配给视图:

    $view->assign('article', $article);
    

    如果你这样做,你通常不需要分配很多东西。 (如果你这样做了,也许你的页面做了太多不同的事情。)

    【讨论】:

    • 我完全明白你在说什么,但是考虑到 php/includes 的工作方式,一旦将视图包含到要显示的控制器中,控制器中的所有变量都会成为视图的局部变量。这就是我很难克服的。我想只有将这些传递给可能对数据执行进一步操作的 View 类才有意义……但这引出了一个问题,即该操作是否真的应该发生在 View 类中。
    • @ChrysG.,这些控制器变量不会成为视图的本地变量,除非您在控制器的方法中嵌入文字 include。但即使你这样做,我还是会坚持最小化耦合度的原则。
    • 他不理解的是函数和方法不继承它们被调用的范围。
    • 我终于明白了这一点,如果您在某些时候不使用包含,那么如何渲染/显示视图?在某些时候,视图文件需要以某种方式包含在 index.php 文件中,该文件始终提供服务。我能看到不使用包含的唯一方法是使用重定向,但我从未见过任何(网络)MVC 使用重定向来显示内容。
    • @Chrys G. 视图确实包含模板...但是视图没有控制器的变量范围...
    【解决方案4】:

    由于控制器变量所在的范围。除非您将所有内容都设为全局(非常糟糕的主意),否则您的概念将不起作用。

    【讨论】:

    • 据我目前所见,include 将所有内容都纳入范围,因为它被包含在声明变量的同一函数中。
    • @Chrys G. 是的,include 继承了 render() 方法范围的所有内容,但 render() 方法不继承控制器的任何内容。
    • 我想我到了我不理解的部分。我知道 render() 不会从控制器继承任何东西,因为它是另一个类的方法,例如这个 Java,肯定需要将变量传递给 View 类/视图文件。但是既然 include 将 Controller 的 main() 方法中声明的所有变量都带入了作用域,那么作用域的问题难道不是一个有争议的问题吗?
    • @Chrys G. include 仅具有与调用它的位置相同的范围。因为它是在 render 方法中调用的,所以它与 render 方法共享相同的范围。 include 基本上与将文件的内容复制并粘贴到包含语句所在的代码中相同。这有意义吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    相关资源
    最近更新 更多