在MVC php程序中$ view是否正确使用全局变量?

我明白应该避免全局变量。 作为初学者,我试图了解在MVC原则下构建的动态Web程序中是否创建全局视图变量是全局变量是个好主意的情况之一。</ p>

In 我的程序,我在index.php中创建了$ view(作为一个包含空数组的对象),并在使用它的控制器中将其转换为全局。</ p>

谢谢!< / p>

JDelage </ p>
</ div>

展开原文

原文

I understand that global variables should be avoided generally. As a beginner, I'm trying to understand whether making a $view variable global in a dynamic web program built following MVC principles is one of those cases where globals are a good idea.

In my program, I create the $view (as an object that contains an empty array) in index.php, and turn it into a global in the controllers that use it.

Thanks!

JDelage

4个回答




在我的程序中,我在index.php中创建$ view作为空数组(),并将其转换为 在使用它的控制器中进入全局。</ p>
</ blockquote>

为什么? 如果你的控制器需要 $ view </ code>,那么只需通过构造函数或setter传入它。 可以使用依赖注入始终解决对Globals的依赖性。 </ p>

  // index.php 
$ view = array();
$ controller = new Controller($ view);
$ controller-&gt; doAction() ;
</ code> </ pre>

另外,如果View应该只是一个数组,请重新考虑。 必须在某个时刻呈现视图。 渲染是我在View上看到的一个责任。 数组无法呈现自身,因此我假设您正在其他地方执行此操作。 这将违反单一责任原则。 我宁愿做一些事情(简化</ em>):</ p>

  // index.php 
$ view = new View;
$ controller = new Controller($ view);
$ controller-&gt; doAction();

// controller.php
...
公共函数doAction()
{
... \ \ n $ this-&gt; view-&gt; setTemplate('/ path / to / template');
$ this-&gt; view-&gt; setVar('foo','bar');
$ this-&gt ; view-&gt; render();
}
...
</ code> </ pre>
</ div>

展开原文

原文

In my program, I create the $view as an empty array() in index.php, and turn it into a global in the controllers that use it.

Why? If you controller needs the $view then just pass it in via the constructor or a setter. Dependencies on Globals can always be resolved by using Dependency Injection.

// index.php
$view = array();
$controller = new Controller($view);
$controller->doAction();

Also, please reconsider if the View should be just an array. The View has to be rendered at some point. Rendering is a responsibility I'd see on the View. An array cannot render itself, so I assume you are doing it elsewhere. That would be a violation of the Single Responsibility Principle. I'd rather do something along the lines of (simplified):

// index.php
$view = new View;
$controller = new Controller($view);
$controller->doAction();

// controller.php
...
public function doAction()
{
    ...
    $this->view->setTemplate('/path/to/template');
    $this->view->setVar('foo', 'bar');
    $this->view->render();
}
...

Making a variable global is not a good idea when you using an MVC patterns in a project. There are other solutions that will make use of your MVC more wisely.

If you should have a single use of a resource, use a singleton pattern. Something like

class My_View {

   private $_instance;

   static public function getInstance() {
     if (null === self::$_instance) {
        self::$_instance = new self();
     }
     return self::$_instance;
   }

   private function __construct() { }

   public function __clone() {
      trigger_error("Cannot make copy of this object", E_USER_ERROR);
   }

   // add public methods and/or properties here...
}

and get that view object anywhere with

$view = My_View::getInstance();

This way, you don't have global variables and you are using best OO practices.

However, as others have pointed out, having a singleton view is not necessarily a good idea... A probably better approach would be to make your dispatcher code create a new view and set it to the controller being called, so the controller would have a view available and access it directly.

The view (not being a singleton) could also be a public property, or accessible though a public method of an application singleton; My_Application::getInstance()->getView(); that could also hold the current configuration, paths,

The name My_view suggested is merely an example. Using some sort of naming convention helps organize the code and helps getting rid of all those include/require calls in your script headers. This is not in your question's scope, however for clarity's sake, I'll briefly explain :

In your bootstrap, you declare your autoloading function (as defined in the PHP manual) :

// My_Application.php located in /path/to/lib/My/Application.php
class My_View {

   private $_instance;

   static public function getInstance() {
     if (null === self::$_instance) {
        self::$_instance = new self();
     }
     return self::$_instance;
   }

   private $_basePath;
   public $view;

   private function __construct() { }

   public function __clone() {
      trigger_error("Cannot make copy of this object", E_USER_ERROR);
   }

   public function initAutoloader($base) {
      $this->_basePath = $base;
      spl_autoload_register(array($this, 'autoload'));
   }

   public function autoload($name) {
      require $this->_basePath . str_replace('_', '/', $name) . '.php';
   }

   // get the application global view
   public function getView() {
      if (null === $this->view) {
         $this->view = new My_View();
      }
      return $this->view;
   }
}
// perhaps have the parameter being a constant. I.g. APP_BASE_PATH
My_Application::getInstance()->initAutoload('/path/to/lib/');

And simply include the file '/path/to/lib/My/Application.php' and when you will access My_View, the load function will be called with $name = 'My_View' and the function will simply require the file '/path/to/lib/My/View.php' for you. This is not much for one file, but if all classes are namespaces like so, you only need one include (Autoloader) and everything else is loaded automatically.

dtsc1684
dtsc1684 确实! 谢谢你发现了这一点。
大约 10 年之前 回复
dongzang5815
dongzang5815 静态公共getInstance()真的应该是静态公共函数getInstance()吗?
大约 10 年之前 回复
dongluoheng3324
dongluoheng3324 由于PHP 5.3尚未在每个虚拟主机中实现,因此它可以替代“我的\ View”。 这是Zend采用的命名约定,它运行良好。 但无论如何,如果有人想要一堆全局函数,我该如何争辩呢?
大约 10 年之前 回复
duanmianzhou5353
duanmianzhou5353 Rochon,你说:“这个答案组织名称空间中的不同组件”。 但实际上,您在类中组织了不同的组件。 一个类!=命名空间。 虽然两者都提供了一种封装形式。
大约 10 年之前 回复
dongtang1944
dongtang1944 这怎么合乎逻辑? MVC与Singleton模式无关。 它甚至不是一个网络表现模式。 Singleton仅确保特定类只能实例化一次。 就这样。 OP没有要求这样做。 Singleton随处可用仅仅是因为它是通过getInstance()方法静态访问的。 但是 - 如果你没有使用命名空间 - 做MyClass :: foo()与使用常规函数没什么不同,例如 myclass_foo(),因为静态调用是对全局命名空间的调用,具有相同的冲突风险。
大约 10 年之前 回复
dongzhu6900
dongzhu6900 这个问题引用了使用MVC模式,暗示另一种模式只是逻辑上的。 而且,由于“在动态网络程序中创建$ view变量全局”是问题描述的一部分,因此建议使用Singleton模式。 此外,这个答案组织命名空间中的不同组件,从而允许类的自动加载。 最后,我同意视图不应该只有一个实例。 我使用ZF,尽管我通常使用一个注册的视图实例,但Zend_View类本身并不是单例,但这不是OP的意图。
大约 10 年之前 回复
drep94225
drep94225 我说它确保了应用程序中某种形式的完整性,我从不谈论类的完整性。 如何在全球范围内对类进行硬编码? ..这是一个班级名字! PHP保留了类名称的注册表和代码所在的位置,我可以说全局范围内的函数......也在全局范围内,甚至是最糟糕的! 没有具有全局功能的真实结构; 没有封装,没有自动加载,但整个应用程序中有一堆include和require语句。 在这个意义上,Wordpress和Drupal是一场噩梦; “那个xyz函数的主体在哪里??”
大约 10 年之前 回复
dsmgcse8876
dsmgcse8876 Singleton不是确保课程完整性的单身人士。 这是班级本身。 单身人士不是最好的OO练习。 它们是代码味道。 My_View是一个硬编码的类名。 因此,它依赖于全局范围(或​​当前命名空间)。 它没有比使用全局变量更好的方法。 实际上,情况更糟,因为全局$视图可以更容易地用Mock代替硬编码类。 这并不是说使用全局变量。 两个都很糟糕。 另外,为什么只有一个View实例呢?
大约 10 年之前 回复
duangang79177
duangang79177 不同之处在于你不能“设置”一个单例,而你可以轻松地替换一个全局变量。 单身人士确保应用程序具有某种形式的完整性。
大约 10 年之前 回复
dongpaipu8394
dongpaipu8394 只有当这种模式成为选择模式时才是不好的做法:)否则(就像在这种情况下)它是一个比使用全局变量更好的解决方案。 不应该有两个或更多的单身人士,而是应该创造一个独特的单身人士,无论需要分享什么。 ......可以举例说明许多情景,但原则仍然存在; 它不应该是我想到的第一个模式,我同意。
大约 10 年之前 回复
douhui3760
douhui3760 单身人士只是一个精心设计的语义解决方法,可以通过其他名称来创建全局变量。
大约 10 年之前 回复
dongmo1708
dongmo1708 但是:使用单身人士通常是不好的做法,对于一些特殊情况是安全的。
大约 10 年之前 回复



全局变量应该避免</ em>,为true。 然而,它们对于保持全局状态非常有用 - 它不会导致相互耦合 - 特别是在$ config数组/对象中。</ p>

但在你的情况下,我不确定$ view 是个好主意。 首先,我相信你所组装的是输出数据。 MVC中的“视图”更像是一个输出模板,我相信你的index.php是什么? 如果是这样,那么你实际上正在组装$ model。 不确定。

理论上更清晰,然后明确地将此变量传递给控制器​​。 但是,如果真的只有那个一个</ strong>全局变量,并且你保证不会过度使用它,那么将它传递给全局就可以了。</ p>

但你也可以遵循 提到单身模式。 但是我建议使用过程变量,因为它更清晰:</ p>

  function view(){
static $ view;
if(!isset($ view)){ $ view = new ArrayObject(); }
返回$ view;
}
</ code> </ pre>

这样你可以使用 $ view = view(); </ code>来本地化它 你的控制器,继续使用它作为数组 $ view [“xy”] = </ code>和同时作为对象 $ view-&gt; xy = </ code>。

或者 只需在模板中写 print view() - &gt; title; </ code>。</ p>
</ div>

展开原文

原文

Global variables should be avoided, true. They are however useful for holding global state - that doesn' lead to intercoupling - as in specifically a $config array/object.

But in your case, I'm not sure the $view is a good idea. Firstly, I believe what you are assembling is output data. The "view" in MVC is more of a output template, what I believe your index.php is? If so, then you are actually assembling the $model. Uncertain.
It's theoretically cleaner to pass this variable to the controllers explicitely then. If it's however really only that one global variable, and you promise not to overdo it, passing it around as global is ok.

But you could also follow the mentioned singleton pattern. However I'd recommend the procedural variant, because it's cleaner:

function view() {
    static $view;
    if (!isset($view)) { $view = new ArrayObject(); }
    return $view;
}

This way you could use $view=view(); to localize it in your controllers, keep using it as array $view["xy"]= and as object $view->xy= at the same time.
Or just write print view()->title; in the template.



我遇到的这个问题的解决方案是从基本控制器扩展控制器。 在该基本控制器中,实例化 $ data </ code>属性; 然后,新视图数据将附加到此属性。 例如:</ p>

  class PageController扩展BaseController {

函数IndexAction(){
$ this-&gt; data ['title'] =“Page Title”;

$ this-&gt; data ['content'] =“&lt; p&gt; Page content。&lt; / p&gt;”;

$ this-&gt; render();
}
}
</ code> </ pre>

渲染方法(可以在方法运行后自动加载,而不是显式加载)然后使用 $中保存的数据组装模板 数据</ code>数组。</ p>

希望这有助于您实现可行的解决方案。</ p>
</ div>

展开原文

原文

A solution to this problem I've seen is having controllers extend from a base controller. Within that base controller a $data property is instantiated; new view data is then appending to this property. For example:

class PageController extends BaseController {

    function IndexAction() {
        $this->data['title'] = "Page Title";
        $this->data['content'] = "<p>Page content.</p>";

        $this->render();
    }
}

The render method (which could be loaded automatically after a method has ran, rather than being explicitly) would then assemble a template using the data held within the $data array.

Hope this helps and you're able to implement a working solution.

douduidui1046
douduidui1046 那么那应该没问题,但也没有使用“全局”变量。 不确定是不是你不理解上面的例子,或者PHP的全局定义。
大约 10 年之前 回复
duandai7601
duandai7601 是的,这就是我所做的。
大约 10 年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐