2

我的问题需要一些设置,所以请多多包涵:

我转而使用 View Helpers 从模型中获取数据,而不是将其洒在控制器上(向Eric Clemmons 致敬)。它在那里更加可重用和灵活。我就喜欢!

我通常做的是将模板放在 index.phtml 中,然后当我需要从模型中获取一些东西时,将那个片段放在 detail.phtml 中,这样逻辑就尽可能地避开了。

但是,我开始看到需要重用的变量。例如,类别名称。现在您不想使用视图助手一遍又一遍地从模型中获取猫的名称。虽然你可以缓存它,但这显然太麻烦了。

所以我开始在 detail.phtml 中使用几行 php 来设置变量。而且它不再闻起来不对劲了。视图不应该有太多的逻辑。

那么大家怎么说呢?如果 var 被重用,把它放在控制器中?或者不介意在视图中设置几个变量?

编辑:Alan Storm 询问了一个 viewhelpers 的例子:

详细信息.phtml:

<ul id="productList">

<? foreach($this->getProductById($id) as $product) : ?>
    <li><?= $this->escape($product['name']) ?></li>
<? endforeach; ?>

</ul>

(为反短标记者的攻击做好准备)

另一个编辑:我看到不可能有 2 个正确答案。那好吧...

4

7 回答 7

5

Controller 和 View 都不是用来存储应用程序状态的。这就是模型的用途。

请记住,MVC 中的“模型”不是数据库表!模型是您为应用程序实现业务逻辑的地方,将其存储在数据库中是模型的内部实现细节。但是你可以在你的应用程序中拥有与数据库无关的模型。

于 2009-08-12T22:14:07.393 回答
2

简短的回答:恕我直言,是的,把它放在控制器中。

原因:

1)将变量传递给视图的控制器是更典型的MVC。

2) 可维护性:当我在 3 个月内再次访问视图时,我不想在相邻的视图/模板中四处寻找变量。现在你回到意大利面条代码,不得不猜测特定变量的来源。

于 2009-08-12T22:15:37.517 回答
2

我不太喜欢这种变量的想法:它在视图或控制器中添加了更多代码,感觉不太好。

另一方面,我喜欢缓存的这种想法……如果您认为它太复杂/矫枉过正,那就是事件。

为什么不在中间找到一些方法?不使用文件/APC/memcache 之类的缓存,而只是将数据保存在内存中以执行脚本?
您可以为此使用静态变量;在您的类中或直接在方法中(取决于“在类的方法之间共享该缓存是否有意义?”)

为了说明这个想法,这里有一小段代码;考虑这个类:

class A {
    public function test($param) {
        static $cache = array();
        if (isset($cache[$param])) {
            var_dump("cache hit : $param = {$cache[$param]}");
            return $cache[$param];
        } else {
            // Fetch from DB (here, simulated ^^ )
            $cache[$param] = mt_rand(0, 9999);
            var_dump("cache miss : $param = $cache[$param]");
            return $cache[$param];
        }
    }
}

test方法使用一个静态变量(该变量只有一个实例,由该类的任何实例共享)来存储从数据库中获取的数据。

如果你这样称呼它:

$a = new A();
$b = new A();

$a->test(10);   // miss
$a->test(15);   // miss
$b->test(10);   // hit
$b->test(25);   // miss
$a->test(25);   // hit

你会得到这个:

string 'cache miss : 10 = 3745' (length=22)
string 'cache miss : 15 = 7800' (length=22)
string 'cache hit : 10 = 3745' (length=21)
string 'cache miss : 25 = 8623' (length=22)
string 'cache hit : 25 = 8623' (length=21)

每次使用新参数调用该方法时,都会错过,然后您转到数据库。但是当一个参数已经使用过一次时调用它时,数据在内存中——你不需要去数据库;-)

那不会有帮助吗?我猜,在你的情况下,A类是视图助手,顺便说一句;-) 并且mt_rand将是一个数据库查询 ^^

作为旁注:对于太大的对象不应该这样做,因为它会使用一些 RAM ......并且没有很多......


编辑:当您使用 Zend 框架时,您可能有兴趣使用Zend_Memory而不是那个静态变量:它处理诸如占用的 RAM 量之类的东西(例如,如果需要,它可以从“缓存”中删除数据),如果我记得正确。

另外:是的,您仍然多次调用该方法...但这比进行查询要好...而且,这样,视图和控制器都不必关心任何类型的“缓存”:这不是他们的工作。

而且:我多年来一直在使用这种技术,没有任何问题(只要我只以这种方式存储小物体,而不是太多);而且我不是唯一一个使用它的人;例如,Drupal 也使用它。

于 2009-08-12T22:16:06.033 回答
2

我不确定您所说的确切技术。以下假设您正在View Helpers上创建方法,这些方法通过包装对模型的“获取数据”方法的调用来返回信息。这使您远离许多其他 PHP MVC 框架所采用的被动视图模式。视图直接进入模型获取数据。您的顾虑是多次调用视图助手将导致模型两次获取数据。这是一个潜在的性能问题,似乎很容易避免。

//example of how I'm assuming you're using view helpers
echo $this->viewHelperName->modelName->getDataIWant('key');

如果这准确地描述了您的问题,那么“如果我需要使用它两次,请在控制器中设置一个视图变量,否则只使用视图助手”方法可能是错误的。这更多是我个人的偏好,但是无论您选择哪种方法从模型中获取数据到您的视图中,您都应该在整个应用程序中坚持使用。

您在这里尝试解决的问题是“直接从模型中获取数据具有很高的性能成本”。这是模型实现应该解决的问题。这不是应该通过 janky 编码风格来解决的问题 :)

正如您已经提到的,最好的解决方案是缓存。如果您很聪明,缓存不必“太麻烦”。

public function getDataIWant($key, $clear_cache=false)
{
    if(!array_key_exists($key, $this->_cache) || $clear_cache)
    {
        $this->_cache[$key] = parent::getDataIWant[$key];
    }

    return $this->_cache[$key];
}

如果缓存对于您使用模型的方式不可行,那么我建议向您的模型添加一个方法来获取您想要的数据,并使用提取来定义视图范围中的变量。

class MyModel
{
    ...
    function getDataForFooView
    {
        return Array(
            'company_name'=>$this->getCompanyName
        );
    }
    ...
}

...
//top of the view file
<?php extract($this->viewHelper->modelName->getDataForFooView()) ?>
<h1><?php echo $company_name; ?></h1>

它仍然有点笨拙,但是您的视图文件(顶部的一行)会保持一致,闻起来会更少。也就是说,缓存是执行此操作的“正确™”方式。避免这种情况只是用一种气味换另一种气味。当您定义视图变量(直接在视图中或通过在控制器中设置)时,一种思考方式是您已经在使用缓存,只是以一种随意的方式。

于 2009-08-12T23:19:47.387 回答
1

我在我的控制器中使用它: $this->view->someVariable = 1;

....在视图中

视图->一些变量

于 2009-08-13T00:14:50.637 回答
1

我在控制器中做了几乎所有的变量分配。为什么?我有多个视图可用于每个操作。我正在使用 ContextSwitch 为 ATOM、RSS 和纯 HTML 中的页面提供提要。在许多方面,我可以将其扩展到 API(json 或 xml)和 oEmbed 处理。现在,我在我的模型对象列表中进行分配,因为不同的视图需要来自我的模型的不同数据,但我只是访问我分配的内容。

好消息是我可以编写一次控制器,然后以我想要呈现数据的方式编写视图脚本。我在这里和那里使用了一些视图助手来获得更多基于视图的逻辑。

现在我想你可以使用更复杂的视图助手来做到这一点(并对你希望在请求中记忆/缓存的数据使用某种注册表),但看起来你隐藏的东西比你需要的更深,但那可能见仁见智。

于 2009-08-13T14:29:45.940 回答
1

所以我开始在 detail.phtml 中使用几行 php 来设置变量。而且它不再闻起来不对劲了。视图不应该有太多的逻辑。

视图可以包含任意数量的显示逻辑。业务逻辑应该在模型和/或控制器中,这取决于您喜欢重模型还是轻模型。

在我自己的工作中,我倾向于在控制器中分配所有变量,除非我使用视图助手来呈现导航、广告等。视图助手确实适用于您将在网站的许多部分重复使用的东西。

当将控制器中的变量分配给视图时,我有一个记录集,我倾向于循环遍历该记录集并将它们推送到关联数组中。我没有将实际的记录集传递给视图,而是将它传递给这个数组。

这样做的原因是我可以:

  1. 处理控制器中显示的值,而不是视图(电话:1234567890 变为 123-456-7890)
  2. 在控制器中进行任何连接或其他获取
  3. 将琐碎的显示逻辑排除在视图之外(即为偶数行和奇数行设置 css 类等)

示例控制器:

$count = 0;
$list = array();
$result = mysql_query("select * from items limit 10");
while($item = mysql_fetch_object($result))
{
   if($count % 2 ==0){ $css_class = 'even'; } else { $css_class = 'odd'; }
   $count++;
   $item->css_class = $css_class;

   if($item->first_name && $item->last_name)
   {
      $item->name = $item->first_name.' '.$item->last_name;
   }
   else
   {
      $item->name = $item->username;
   }

   $list[] = $item;
}
$this->view->list = $list;

示例视图:

<?foreach($this->list as $item):?>
<tr class="<?=$item->css_class?>">
    <td><?=$this->escape($item->name)?></td>
</tr>
<?endforeach;?>
于 2009-08-18T13:05:11.157 回答