Для начала давайте разберемся с тем что такое "правильно". Правильно в контексте вопроса - это максимально гибко. В приведенных вами ссылке "роутер" влияет на то, как будет устроена вся система. То есть в них мы сначала делаем допущение "у нас будут контроллеры, модели и представление, что бы как в рельсах но по другому).
Роутер же не должен ничегошеньки знать о контексте своего использования. Вот это будет правильно. Мы просто должы скормить ему какие-то правила маршрутизации, задающие соответствие "uri => mixed" к примеру, а так же иметь возможность скормить ему строчку что бы тот сказал кого все же вызывать.
Все, на этом зона ответственности "роутера" заканчивается. Грубо говоря самая примитивная реализация роутера:
// наш примитивный роутер
function getRoute(array $rules, $uri) {
return $rules[$uri] ?? null;
}
// использование роутера
$action = getRoute([
'/' => 'indexPage',
'/about' => 'aboutPage',
'/blog' => 'blogPage'
], '/about');
// больше нам уже роутер не нужен
// вызываем действие
call_user_func($app, $action);
Далее уже мы можем решать как нам будет удобнее организовать работу с правилами. То есть сразу мы видим что тут статическая карта маршрутов, а стало быть... мягко скажем не гибко. Тут мы можем использовать либо uriTemplates либо просто регулярные выражения либо придумать свою надстройку над регулярками для более удобного составления правил.
Сами же значения карты роли роутеру играть не должны. Хотя мы можем добавить туда какие-либо дополнительные ограничения, вроде поддерживаемый HTTP метод и т.д. Но в этом плане проще сделать так:
$rules = [
[ 'uri' => '/blog/page{pageNumber:\d+}', 'method' => ['GET', 'HEAD'] ]
];
далее мы можем сделать загрузчики правил и прочую чушь. Но повторюсь - цель роутера - на основе строчки, представляющей URI выбрат из списка маршрутов подходящий. Роутер не должен больше ничего уметь.
Запуском же конкретных действий по найденному маршруту пусть лучше занимается другой компонент.