У вас может быть и модель, и прдставление и контроллер хоть в одном файле, суть то не в этом.
MVC описывает не все приложение (есть Model2 которое убого но описывает все приложение, но я бы не рекомендовал вам сейчас на него ориентироваться). Оно описывает только "как сделать так, что бы приложение ничего не знало о UI".
Например есть "модель" представляет собой "переднюю часть приложения" или ее публичный интерфейс (как интерфейс объекта можно воспринимать если упрощать). Это не один объект, а как правило множество разных объектов. Но контроллер работает только с вершиной этого "графа", и инкапсуляция не даем ему знать ничего о "нутре".
Далее, у нас есть представление. Вопреки вашему мнению, представление это не html а http. Поскольку PHP должен сформировать именно HTTP ответ (так или иначе, при помощи echo и header или при помощи абстракций над http). Просто обычно сайтики в качестве тела ответа содержат html. Но намного проще воспринимать "представление" как HTTP ответ. "шаблонизаторы" в этом плане не относятся к представлению, это способ его генерации. Сделаем допущение что весь view в нашем MVC это обычный HTTP ответ. Просто кусок текстовой инфы выплюнутый в буфер вывода. Помимо HTTP есть еще варианты: CLI или консольные скрипты, у них сфой формат представления. А еще есть менеджеры очередей и кучи других вариантов.
Так же есть еще HTTP запросы, которые по сути являются частью представления, а точнее может восприниматься как какое-то действие пользователя. Причем под пользователем я подразумеваю не обязательно живого человека, а все что угодно, что может отправлять запросы. Браузеры, боты, краулеры, ваше же приложение.
Ранее мы уже сказали что "шаблонизаторы" это не часть представления а только способ его получения. Где мы должны использовать шаблонизатор тогда? Как сделать так, что бы наша "модель" или точнее наше приложение ничего не знало об этом "шаблонизаторе" (или сериалайзере, или json_encode, или еще чем-то там)? Положим между представлением и моделью что-то промежуточное - контроллер.
Опять же контроллер - это не обязательно один объект. Это может быть целая цепочка объектов, которая может передавать запросы друг дружке и что-то с ними делать. Например один "контроллер" глянет мол "ага, он в качестве тела запроса прислал json - десериализуем". А второй контроллер такой "ага, он должен быть авторизован - надо проверить". Ну и т.д. покуда мы не дойдем до последнего контроллера в цепочке, который уже будет дергать "один" метод модельки. Это слой адаптеров между http и нашим приложением. Вот ключевая мысль MVC на бэкэнде (или ели точнее Mediating controller MVC или MVA, паттерн который реализован в большинстве современных бэкэнд фреймворков).
Зачем нужно отделять UI от приложения? потому что что-то из этого явно меняться будет чаще и не одинаково. А еще можно распаралелить работу. А еще можно заменить реализацию одной из частей без вреда для другой. Словом мы получаем намного больше гибкости, но только если приложение ничего не знает о представлении.. В противном случае мы получаем антипаттерн под названием smart ui, для борьбы с которым 40 лет назад и придумывали MVC.