Это называется di (внедрение зависимостей)
в $app->get строка 'App\Controllers\UserController:listUsers' преобразуется в App\Controllers\UserController и метод listUsers с помощью explode(':', 'App\Controllers\UserController:listUsers');
После этого с помощью инструмента внедрения зависимостей (в случае со slim используется Pimple со своими загрузчиками объектов) создается объект и по умолчанию передает сам себя в конструктор (так ты в конструкторе получаешь container который по сути объект pimple который реализует psr\container
Далее идет вызов у объекта что был получен на прошлом шаге выбранного метода если он был указан с аргументами current.request и current.response которые определены внутри pimple
Ну и тут выполняется уже твой код ты у pimple запрашиваешь контейнер который отвечает за view, по умолчанию это объект Twig вроде и у него вызываешь метод render в котором у тебя вроде перепутанны аргументы (в начале имя шаблона, потом аргументы для этого шаблона в виде массива)
Рендерится шаблон на выходе получается строка, это строка помещается в response внутри app после вызова метода, если результат метода не response и далее этот response отсылается пользователю
В общих чертах примерно так, со своими нюансами и еще у slim есть несколько версий которые существенно отличаются.