在 Zend Framework 中,在视图中设置变量还是在控制器中设置变量更好?

发布于 2024-07-30 19:41:13 字数 888 浏览 4 评论 0原文

我的问题需要一些设置,所以请耐心等待:

我开始使用视图助手从模型中获取数据,而不是将其散布在控制器上(提示 埃里克·克莱蒙斯)。 它的可重用性和灵活性要高得多。 我就喜欢!

我通常做的是将模板放在index.phtml中,然后当我需要从模型中获取某些内容时,将该片段放入detail.phtml中,这样逻辑就尽可能远离。

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

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

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

编辑:艾伦·斯托姆(Alan Storm)要求提供 viewhelpers 的示例:

detail.phtml:(

<ul id="productList">

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

</ul>

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

另一个编辑: 我发现不可能有两个正确答案。 那好吧...

My question needs a bit of setup, so please bear with me:

I became a convert to using View Helpers for getting data from a model rather than sprinkling it all over the controllers (hat tip to Eric Clemmons). It's much more reusable and flexible there. I just love it!

What I usually do, is lay out the template in the index.phtml, and then when I need to get something from a model, put that snippet in a detail.phtml, so logic is as far out of the way as possible.

However, I start to see the need for variables that get reused. For example, the category name. Now you don't want to use a view helper to get the cat name from a model over and over again. Although you can cache it, it's obviously way too big of a hassle.

So I started using a couple of lines of php in the detail.phtml to set variables. And it doesn't smell right anymore. Views shouldn't have too much logic.

So what say you all? If the var gets reused, put it in the controller? Or don't mind a couple vars set in the view?

EDIT: Alan Storm asked for an example of viewhelpers:

detail.phtml:

<ul id="productList">

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

</ul>

(bracing myself for attack of the anti-short-taggers)

ANOTHER EDIT:
I see there can't be 2 right answers. Oh well...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

往日情怀 2024-08-06 19:41:13

控制器和视图都不用于存储应用程序状态。 这就是模型的用途。

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

Neither the Controller nor the View are for storing application state. That's what the Model is for.

Keep in mind that a "Model" in MVC is not a database table! The Model is where you implement business logic for the application, and storing it in a database is an internal implementation detail of a Model. But you can have Models in your app that have nothing to do with a database.

孤单情人 2024-08-06 19:41:13

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

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

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

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

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

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];
}

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

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>

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

I'm not sure the exact technique you're talking about. The following assumes you're creating methods on View Helpers that return information by wrapping calls to your model's "get data" methods. This gets you away from the Passive View pattern employed by many other PHP MVC Frameworks. The views are going directly to the models for their data. Your concers is multiple calls to the the view helper will cause the model to fetch the data twice. This is a potential performance problem that seems easily avoidable.

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

If that accurately describes your problem, the "if I need to use it twice, set a view variable in the controller, otherwise just use the view helper" approach is probably the wrong one. This is more my personal preference, but whichever approach you choose for getting data from the models to your view, you should stick to throughout your application.

The problem you're trying to solve here is "fetching data directly from the models has a high performance cost". This is a problem that the model implementation should fix. It's not something that should be fixed by janky coding style :)

The best solution, as you've already mentioned, is caching. Caching doesn't have to be "too big of a hassle" if you're smart about it.

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];
}

If caching isn't viable for the way you're using models, then I'd suggest adding a method to your model for getting the data you want, and using extract to define variables in the view scope.

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>

It's still kind of janky, but you get a consistency in your view files (a single line at the top) that will smell less. That said, caching is "The Right™" way to do this. Avoiding that is just trading one smell for another. One way to think about when you define a view variable (either directly in the view or by setting it in the controller) you're already using caching, just in a haphazard fashion.

梦纸 2024-08-06 19:41:13

简短的回答:恕我直言,是的,将其放入控制器中。

原因:

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

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

Short answer: IMHO, yes put it in the controller.

Reasons:

1) The controller passing variables into the views is more typical MVC.

2) Maintainability: When I re-visit the view again in 3 months, I don't want to have to look around in adjacent views/templates looking for variables. Now you are back to spaghetti code, having to guess where a particular variable originated from.

呆头 2024-08-06 19:41:13

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

另一方面,我喜欢缓存的想法...事件,如果你认为它太复杂/杀伤力太大了​​。

为什么不在中间找到某种方法呢? 不使用像 file/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方法使用一个静态变量(该变量将有一个且只有一个实例,由该类的任何实例共享)来存储从D B。

如果你这样调用:

$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...并且没有很多 RAM...

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

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

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

I don't really like this idea of variables : it add more code either in the view or the controller, and it doesn't feel nice.

On the other hand, I like this idea of cache... Event if you think it's too complex / overkill.

Why not find some way in the middle ? Not use some cache like file/APC/memcache, but just keep the data in memory for the execution of the script ?

you can use a static variable for that ; either in your class, or directly in the method (depending on "does it make sense to share that cache between methods of the class ?")

To illustrate this idea, here's a quick portion of code ; consider this class :

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];
        }
    }
}

The test method uses a static variable (there will be one, and only one instance of that variable, shared by any instances of the class) to store the data that has been fetched from the DB.

If you call this that way :

$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

You'll get this :

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)

Each time the method is called with a new parameter, it's a miss, and you go to the DB. But when it's called when a parameter already used once, the data is in memory -- and you don't go to the DB ;-)

Wouldn't that help ? I'm guessing, in your case, the A class is the view helper, btw ;-) ANd the mt_rand would be a DB query ^^

As a sidenote : this should not be done for too big objects, as it will use some RAM... and don't have lots of those...

Edit : as you are using Zend Framework, you might be interested in using Zend_Memory instead of that static variable : it deal with stuff like the amount of RAM taken (it can delete data from the "cache" if needed, for instance), if I remember correctly.

Also : yes, you are still calling the method many times... But it's better than doing the query... and, this way, neither the View nor the Controller has to care about any kind of "cache" : it's not their job.

And also : I've be using this technic for years without any problem (as long as I only store small objects this way, and not too many of them) ; And I'm not the only one using this ; Drupal uses this too, for instance.

旧伤慢歌 2024-08-06 19:41:13

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

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

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

I do almost all variable assigns in the controller. Why? I have multiple views available for every action. I'm using ContextSwitch to serve up feeds for pages in ATOM, RSS and then plain HTML. In many ways i could extend this to an API (json or xml) and oEmbed handling. Now, I'm assigning in my list of model objects, since different views need different data from my models, but I'm just accessing what I've assigned.

The nice thing is I can write the controller once, then write the view script in the way I want to present the data. I'm using a few view helpers here and there for more view-based logic.

Now I guess you could do this with more complex view helpers (and use some sort of registry for data you wish to memoize/cache in the request), but it seems like then you're hiding stuff deeper than you need, but thats maybe a matter of opinion.

坏尐絯℡ 2024-08-06 19:41:13

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

....
在视图

view->someVariable中

I am using this in my controllers:
$this->view->someVariable = 1;

....
in the view

view->someVariable

-柠檬树下少年和吉他 2024-08-06 19:41:13

<块引用>

所以我开始在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;?>

So I started using a couple of lines of php in the detail.phtml to set variables.
And it doesn't smell right anymore. Views shouldn't have too much logic.

Views can contain as much display logic as you like.
Business logic should be in the model and/or controller, depending on if you prefer heavy or light models.

In my own work, I tend to assign all variables in the controller, unless I am using a view helper to render the navigation, ads, etc. View Helpers are really for things you'll re-use on many parts of the site.

When assigning variables in the controller to the view, and I have a recordset, I tend to loop through that recordset and push them onto an associative array. Instead of passing the actual recordset to the view, I pass it this array.

The reason for this is so that I can:

  1. Manipulate values for display in the controller, not the view (phone: 1234567890 becomes 123-456-7890)
  2. Do any joins or other fetching in the controller
  3. Keep trivial display logic out of the view (i.e. setting the css class for even & odd rows, etc)

Example Controller:

$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;

Example View:

<?foreach($this->list as $item):?>
<tr class="<?=$item->css_class?>">
    <td><?=$this->escape($item->name)?></td>
</tr>
<?endforeach;?>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文