Michael Korte – Senior Full-Stack Developer Freelancer aus Dortmund

Ziel dieses Teils

In diesem Abschnitt entsteht zum ersten Mal etwas, das sich für Außenstehende wie eine „Seite“ anfühlt.

Technisch tun wir aber nur eines: Wir treffen eine Entscheidung auf Basis der URL.

  • Router registrieren
  • erste Route definieren
  • Controller als Ziel
  • Error-Controller als Standardweg

5.1 Routing ist keine Darstellung

Der Router beantwortet genau eine Frage:

Welche Entscheidung wird getroffen?

Welcher Controller ist zuständig?
Nicht: welche Seite, nicht: welches Template.

Alles andere passiert später.

5.2 Router registrieren (Bootstrap)

Der Router wird explizit im Bootstrap vorbereitet.

<?php
// App/Bootstrap.php

use Core\\Router;
use App\\Controller\\HomeController;
use App\\Controller\\ErrorController;

private static function register(App $app): void
{
    $router = new Router();

    $router->get('/', [HomeController::class, 'index']);

    // kein Match → ErrorController
    $router->fallback([ErrorController::class, 'error404']);

    $app->setRouter($router);
}

Wichtig: Der Fallback ist kein Sonderfall, sondern der normale Weg, wenn keine Route passt.

5.3 Der erste Controller

Controller sind Entscheidungsinstanzen. Sie erzeugen noch kein HTML.

<?php
namespace App\\Controller;

use Core\\PageContext;

final class HomeController
{
    public function index(): PageContext
    {
        $page = new PageContext();

        $page->withData([
            'message' => 'Hallo Welt'
        ]);

        return $page;
    }
}

Wichtige Beobachtung

Der Controller gibt keinen String zurück, sondern einen PageContext.

5.4 ErrorController als normaler Controller

Fehlerseiten sind keine Sonderlogik, sondern reguläre Controller-Ziele.

<?php
namespace App\\Controller;

use Core\\PageContext;

final class ErrorController
{
    public function error404(): PageContext
    {
        $page = new PageContext();

        $page
            ->withStatus(404)
            ->withData([
                'title' => 'Seite nicht gefunden'
            ]);

        return $page;
    }
}

Der Router entscheidet, dass es ein Fehler ist – der Controller entscheidet, wie damit umgegangen wird.

5.5 Warum hier noch nichts gerendert wird

Auch jetzt haben wir noch:

  • kein Template
  • kein HTML
  • keine Assets

Das ist Absicht.
Der Controller beschreibt nur den Seitenzustand.

Trennung greifbar

Entscheidung ≠ Darstellung
Zustand ≠ Ausgabe

Übergang zu Teil 6

Jetzt existiert erstmals ein vollständiger Ablauf:

  • Request
  • Router
  • Controller
  • PageContext

In Teil 6 folgt der entscheidende Schritt: Rendering – und warum nur der Renderer HTML erzeugt.