Не могу понять MVC в PHP

113
03 декабря 2019, 04:00

На просторах сети, спустя очень большой объём времени, мне удалось найти самый простой пример шаблона проектирования MVC в PHP. Но я никак не могу понять его логики. Куда двигаться дальше, куда заполнять контент и как это делать в соответствии с шаблоном. Помогите понять. Уже несколько недель пытаюсь понять его, а никак. Сам пример:

class Model
{
  public $text;
  public function __construct()
  {
    $this->text = 'Hello World!';
  }
}
class View
{
  private $model;
  public function __construct(Model $model)
  {
    $this->model = $model;
  }
  public function output()
  {
    return '<a href="index.php?action=textclicked">' . $this->model->text . '</a>';
  }
}
class Controller
{
  private $model;
  public function __construct(Model $model)
  {
    $this->model = $model;
  }
  public function textClicked()
  {
    $this->model->text = 'Text Updated';
  }
}
$model = new Model();
$controller = new Controller($model);
$view = new View($model);
if (isset($_GET['action']))
{
  $controller->{$_GET['action']}();
}
echo $view->output();

Я не понимаю что выполняет команда:

class Controller
{
  private $model;
  public function __construct(Model $model)
  {
    $this->model = $model;
  }

Я не понимаю кто кого и как загружает. Вообще ничего непонятно(

Answer 1

Давайте попробуй доступно объяснить, свое представление:

MVC- это идея, не реализация, не набор из 3-ех классов и т.д. Это абстрактная концепция которая помогает решить архитектурные вопросы Вашего проекта предложенным путем.

Самая распространенная версия MVC выглядит так: поступает запрос (например запрос главной страницы сайта), Ваш скрипт запускает контроллер для главной. Контроллер в данном случае тот кусок кода, который отвечает за логику, логика в данном случае - показать пользователю главную страницу. Для формирования главной страницы - нужно обратиться к части, где хранится визуальное оформление страницы (шаблон), это наш условный View. Но вот незадача, в этом коде шаблона есть цикл для вывода новостей, новости хранятся в БД, т.к. мы это знаем мы в контроллере дописываем логику которая обратится к Model и получит новости из бд. Модель - чаще всего представляет класс, который описывает один объект, например класс для работы с новостями. Собственно вот вам и MVC, если еще проще то можно сказать так: это 3 папочки, где в одной: файлы с логикой конкретных страниц (контроллер); в другой: файлы для работы с БД, каждый файл - отдельный объект (модели); В третьей: файлы с визуальным представлением (шаблоны).

Надеюсь мой пример был достаточно понятен, MVC - это просто идея, не более. У этой идеи есть куча реализаций и куча модификаций. Например то что я вам написал, это не классическая версия идеи, а доработанная практикой, классика подразумевает точку входа не контроллер, а View, который запрашивает самостоятельно контроллер и модель. Но и текущий пример это не пик, данная идея имеет ряд минусов, поэтому есть доработки, например HMVC.

Еще доступнее объяснить так: можно сравнить с автомобилем, есть идея: что двигатель крутит колеса, машина едет - все довольны. Идея простая, но реализаций куча, кто-то ставит двигатель спереди, кто-то сзади; кто-то крутит передние 2 колеса, кто-то задние, а кто-то и все 4. Но идея сохранена...

По вашему примеру, ни о каком MVC тут речи нет. Ваш пример ближе к классическому представлению, но я покажу более распространенный вариант:

Во-первых, обычно, классы Model, Controller используются как родители. Ведь контроллеров, моделей - много, поэтому у каждого свое название. Теперь по порядку:

Модель не модель - если она не содержит запросов к БД (может не содержать запросов (на практике), но в MVC модель подразумевает работу с БД):

class NewsModel extends Model
{
  public $text;
  public function __construct()
  {
    $this->text = <Запрос на получение текста из БД>;
  }
}

Отображение - это просто файлы нашего шаблона, класс View - является условным шаблонизатором и служит для того, чтобы вставить какие-то данные в этот шаблон:

class View
{
  public function render($file, $data)
  {
    // 1) найти файл $file
    // 2) загрузить его содержимое, и вставить в это содержимое $data
    // 3) вывести на экран
  }
}

Вставить содержимое, поясню что это, пусть есть массив:

$data = ['TITLE' => 'Заголовок'];

, в нашем примере - загрузка главной, шаблон пусть называется -Home.tpl и в нем есть строка:

<html>
    <head>
        <title>{% TITLE %}</title>
    </head>
    <body>
        Главная страница
    </body>
</html>

Думаю логично что должно произойти, об этом и речь... Прошу не путать, и понимать что в концепции MVC отображением(view) - считается не класс, а именно наш Home.tpl

Ну и остался контроллер, его задача вызвать модельку, и отображение:

class HomeController extends Controller
{
    public function HomeMain()
    {
        $this->loadNewModel('HomeModel');
        $data['TITLE'] = $this->HomeModel->text;
        $this->view->render('Home.tpl', $data);
    }
}

И осталось вызвать (за это отвечает роутинг):

if (isset($_GET['action']) AND ($_GET['action'] == 'HomeMain'))
{
    // загрузить файл с контроллером (HomeController)
    (new HomeController)->HomeMain();
}

P.S. Как вы могли заметить в контроллере есть методы: $this->loadNewModel, $this->view - эти функции из родительского класса (Controller). Описывать их реализацию я не буду, моя задача донести концепцию и думаю теперь вам все понятно...

Answer 2

Возможно вы в принципе не понимаете, как работают классы и объекты.
А работают они очень просто.
Когда вы создаете класс (давайте возьмем ваш пример) Model:

class Model {
  public $text;
  public function __construct() {
    $this->text = 'Hello World!';
  }
}

В данном классе происходит инициализация свойства $text - это свойство объекта, а не статичная переменная или константа класса, она вызывается через контекст $this->, а не через self::, static::, когда бы она была public static $text;.
Когда вы определите объект в переменной:

$model = new Model();

У вас к свойству $text в конструкторе присваивается $this->text = 'Hello World!'; Так-как, свойство public (чего не рекомендуется делать, а лучше вернуть getter) вы сможете обратиться к этому свойству после передачи его другому объекту или сразу на экран:

echo $model->text;

В вашем случае, у вас Model определяется в конструкторе Controller и View, значит они принимают Model, который собран ранее:

$controller = new Controller($model);
$view = new View($model);

А раз мы отправляем в конструкторы классов, у нас будет доступно свойство $text в обоих классах, но операции можем делать разные.

У вас-же View выводит на экран, а Controller изменяет модель как нужно, допустим если вы обратитесь к адресу: ?action=textclicked вызывает метод $controller->{$_GET['action']}(); у Вас это textClicked, а дальше у вас в модели, изменится свойство $text, а View изменит вывод.

Answer 3

https://phpdelusions.net/articles/mvc

На самом деле мвц - это очень просто. Реально просто. Надо только понимать, с какого конца за него браться.

А браться надо за модель.

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

Модель - это вся логика приложения. Это и есть приложение. А контроллер и вью - это всего лишь один из способов обратиться запросить информацию у приложения, причем не обязательные. К примеру, если у нас REST API, то вью отсутствует как класс. А если мы обращаемся к приложению через командную строку, то нам не нужен контроллер.

Отсюда мы можем сделать несколько выводов

Модель - это не один класс, а целый набор классов. Которые и реализуют всю логику приложения.

Контроллер - это код, который служит для коммуникации между браузером и моделью. Он служит только для тансляции http запросов в команды модели.

Вью работает в паре с контроллером, если по запросу надо отобразить HTML.

READ ALSO
Не работает belongsToMany (Many to Many)

Не работает belongsToMany (Many to Many)

Есть pivot-таблица championship_user:

114
Как задать значения полей по умолчанию в модели eloquent?

Как задать значения полей по умолчанию в модели eloquent?

Есть ли возможность прямо внутри модели App\Post задать значения по умолчанию, например для поля user_id типа:

136
Выбор одного значения из клетки

Выбор одного значения из клетки

Как взять только одно значение из клетки у котороый всего 6 значений?

115