Является ли $ view в программе MVC php правильным использованием глобальных переменных? - PullRequest
1 голос
/ 06 сентября 2010

Я понимаю, что глобальных переменных следует вообще избегать. Как новичок я пытаюсь понять, является ли создание переменной $ view глобальной в динамической веб-программе, построенной по принципам MVC, одним из тех случаев, когда глобальные переменные являются хорошей идеей.

В моей программе я создаю $ view (как объект, который содержит пустой массив) в index.php и превращаю его в глобальный в контроллерах, которые его используют.

Спасибо!

JDelage

Ответы [ 4 ]

4 голосов
/ 06 сентября 2010

В моей программе я создаю $ view как пустой массив () в index.php и превращаю его в глобальный в контроллерах, которые его используют.

Почему?Если вашему контроллеру нужен $view, просто передайте его через конструктор или установщик.Зависимости от глобальных переменных всегда можно разрешить с помощью Внедрение зависимостей .

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

Также, пожалуйста, пересмотрите, должен ли View быть просто массивом.Вид должен быть представлен в какой-то момент.Рендеринг - это ответственность, которую я вижу на View.Массив не может отображаться сам, поэтому я предполагаю, что вы делаете это в другом месте.Это было бы нарушением принципа единой ответственности .Я бы предпочел сделать что-то вроде ( упрощенный ):

// 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();
}
...
1 голос
/ 06 сентября 2010

Глобальные переменные должны быть , избегать , true. Однако они полезны для хранения глобального состояния, которое не приводит к взаимодействию, как, в частности, в массиве / объекте $ config.

Но в вашем случае я не уверен, что представление $ является хорошей идеей. Во-первых, я считаю, что вы собираете выходные данные. «Представление» в MVC - это скорее выходной шаблон, как я полагаю, ваш index.php? Если так, то вы на самом деле собираете модель $. Неопределенный.
Теоретически чётче передать эту переменную в контроллеры. Однако если это действительно только эта одна глобальная переменная, и вы пообещаете не переусердствовать, передав ее как глобальная - это нормально.

Но вы могли бы также следовать упомянутой схеме синглтона. Однако я бы порекомендовал процедурный вариант, потому что он чище:

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

Таким образом, вы можете использовать $view=view();, чтобы локализовать его в ваших контроллерах, продолжая использовать его как массив $view["xy"]= и как объект $view->xy= одновременно.
Или просто напишите print view()->title; в шаблоне.

1 голос
/ 06 сентября 2010

Создание глобальной переменной не очень хорошая идея, когда вы используете шаблоны MVC в проекте.Существуют и другие решения, которые будут более разумно использовать ваш MVC.

Если у вас должен один раз использовать ресурс, используйте шаблон синглтона .Что-то вроде

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...
}

и получить этот объект просмотра где угодно с

$view = My_View::getInstance();

Таким образом, у вас нет глобальных переменных, и вы используете лучшие методы OO.

Однако, как отмечали другие, наличие одноэлементного представления не обязательно является хорошей идеей ... Вероятно, лучшим подходом было бы заставить ваш диспетчерский код создать новое представление и установить его для вызываемого контроллера, чтобы контроллер могиметь доступное представление и обращаться к нему напрямую.

Представление (не являющееся одноэлементным) также может быть общедоступным свойством или доступным через открытый метод одноэлементного приложения;My_Application::getInstance()->getView();, который также может содержать текущую конфигурацию, пути,

Предложенное имя My_view является просто примером.Использование какого-либо соглашения об именах помогает упорядочить код и избавиться от всех вызовов include / require в заголовках ваших скриптов.Это не входит в сферу вашего вопроса, однако для ясности я кратко объясню:

В вашей начальной загрузке вы объявляете свою функцию автозагрузки (как определено в руководстве по PHP ):

// 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/');

И просто включите файл '/path/to/lib/My/Application.php', и когда вы получите доступ к My_View, функция load будет вызываться с $name = 'My_View', и функция просто потребует для вас файл '/path/to/lib/My/View.php',Это немного для одного файла, но если все классы являются такими пространствами имен, как, например, вам нужен только один include (Autoloader), а все остальное загружается автоматически.

0 голосов
/ 06 сентября 2010

Решение этой проблемы, которое я видел, состоит в том, что контроллеры расширяются от базового контроллера.Внутри этого базового контроллера создается свойство $data;новые данные представления затем добавляются к этому свойству.Например:

class PageController extends BaseController {

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

        $this->render();
    }
}

Метод рендеринга (который может быть загружен автоматически после запуска метода, а не явным образом) будет затем собирать шаблон с использованием данных, хранящихся в массиве $data.*

Надеюсь, это поможет, и вы сможете реализовать работающее решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...