Files
guides/templates/Referenz/BeginnerGuide.md
2026-05-25 19:33:48 +02:00

56 KiB
Raw Blame History

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>PHP Anfänger-Guide</title>
<style>
@page {
  size: A4;
  margin: 22mm 20mm 20mm 20mm;
  @bottom-center {
    content: counter(page) " / " counter(pages);
    font-family: -apple-system, "Segoe UI", sans-serif;
    font-size: 8pt;
    color: #888;
  }
  @bottom-right {
    content: "PHP Anfänger-Guide";
    font-family: -apple-system, "Segoe UI", sans-serif;
    font-size: 8pt;
    color: #888;
  }
}
@page :first {
  margin: 0;
  @bottom-center { content: none; }
  @bottom-right { content: none; }
}

* { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --php: #777BB4;
  --php-dark: #4F5B93;
  --php-darker: #2C3E66;
  --ink: #1a1a1a;
  --muted: #5a6470;
  --line: #d8dde3;
  --bg-soft: #f5f5fb;
  --code-bg: #1e2a3a;
  --code-fg: #e6e6e6;
  --plus: #2c8a3e;
  --minus: #c0392b;
}

html, body {
  font-family: Charter, "Source Serif Pro", Georgia, serif;
  color: var(--ink);
  font-size: 10.5pt;
  line-height: 1.55;
}

/* ===== COVER ===== */
.cover {
  width: 210mm;
  height: 297mm;
  padding: 35mm 25mm;
  background: linear-gradient(135deg, var(--php-dark) 0%, var(--php-darker) 100%);
  color: white;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  page-break-after: always;
}
.cover-top { display: flex; align-items: center; gap: 8mm; }
.cover-logo {
  width: 28mm; height: 28mm;
  background: linear-gradient(135deg, var(--php) 0%, white 100%);
  border-radius: 7mm;
  display: flex; align-items: center; justify-content: center;
  font-family: -apple-system, sans-serif;
  font-size: 22pt; font-weight: 800;
  color: var(--php-dark);
}
.cover-meta {
  font-family: -apple-system, sans-serif;
  font-size: 9pt;
  text-transform: uppercase;
  letter-spacing: 2pt;
  opacity: 0.8;
}
.cover-main h1 {
  font-family: -apple-system, sans-serif;
  font-size: 56pt;
  font-weight: 800;
  letter-spacing: -2pt;
  line-height: 0.95;
  margin-bottom: 8mm;
}
.cover-main h1 .accent { color: var(--php); }
.cover-main .subtitle {
  font-size: 16pt;
  font-weight: 400;
  line-height: 1.3;
  opacity: 0.9;
  font-family: -apple-system, sans-serif;
  max-width: 130mm;
}
.cover-bottom {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10mm;
  align-items: end;
  font-family: -apple-system, sans-serif;
}
.cover-promise {
  font-size: 10pt;
  line-height: 1.5;
  opacity: 0.85;
  max-width: 110mm;
  padding-top: 4mm;
  border-top: 1pt solid rgba(255,255,255,0.3);
}
.cover-promise b { color: var(--php); text-transform: uppercase; letter-spacing: 1pt; font-size: 8pt; display: block; margin-bottom: 2mm; }
.cover-tag {
  background: var(--php);
  color: white;
  padding: 3mm 6mm;
  border-radius: 2mm;
  font-weight: 800;
  font-size: 11pt;
}

/* ===== TOC ===== */
.toc { page-break-after: always; }
.toc h2 {
  font-family: -apple-system, sans-serif;
  font-size: 24pt;
  font-weight: 800;
  color: var(--php-dark);
  margin-bottom: 6mm;
  border-bottom: 2pt solid var(--php);
  padding-bottom: 3mm;
}
.toc-section {
  font-family: -apple-system, sans-serif;
  font-size: 9pt;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1pt;
  color: var(--muted);
  margin: 6mm 0 2mm 0;
}
.toc-item {
  display: grid;
  grid-template-columns: 8mm 1fr auto;
  gap: 4mm;
  padding: 2.5mm 0;
  border-bottom: 0.3pt solid var(--line);
  align-items: baseline;
}
.toc-num {
  font-family: -apple-system, sans-serif;
  font-size: 14pt;
  font-weight: 800;
  color: var(--php);
  line-height: 1;
}
.toc-text { font-family: -apple-system, sans-serif; }
.toc-text h3 {
  font-size: 10.5pt;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 0.5mm;
}
.toc-text p {
  font-size: 8.5pt;
  color: var(--muted);
  margin: 0;
}
.toc-time {
  font-family: -apple-system, sans-serif;
  font-size: 7.5pt;
  color: var(--muted);
  background: var(--bg-soft);
  padding: 0.8mm 2.5mm;
  border-radius: 1.5mm;
  white-space: nowrap;
}

/* ===== CHAPTER ===== */
.chapter { page-break-before: always; }
.chapter-head {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6mm;
  align-items: center;
  border-bottom: 2pt solid var(--ink);
  padding-bottom: 4mm;
  margin-bottom: 6mm;
}
.chapter-num {
  font-family: -apple-system, sans-serif;
  font-size: 42pt;
  font-weight: 800;
  color: var(--php);
  line-height: 0.9;
  width: 22mm;
  text-align: center;
}
.chapter-title h1 {
  font-family: -apple-system, sans-serif;
  font-size: 22pt;
  font-weight: 800;
  color: var(--php-dark);
  letter-spacing: -0.5pt;
  line-height: 1.1;
}
.chapter-title .subtitle {
  font-family: -apple-system, sans-serif;
  font-size: 11pt;
  color: var(--muted);
  margin-top: 1.5mm;
}

/* ===== GAP ===== */
.gap {
  background: var(--bg-soft);
  border-left: 3pt solid var(--php);
  padding: 4mm 5mm;
  margin: 4mm 0 6mm 0;
  font-style: italic;
  font-size: 10.5pt;
}
.gap b {
  font-style: normal;
  color: var(--php-dark);
  font-family: -apple-system, sans-serif;
  text-transform: uppercase;
  font-size: 8pt;
  letter-spacing: 1pt;
  display: block;
  margin-bottom: 1.5mm;
}

/* ===== SECTIONS ===== */
.chapter h2 {
  font-family: -apple-system, sans-serif;
  font-size: 14pt;
  font-weight: 700;
  color: var(--php-dark);
  margin: 7mm 0 3mm 0;
  page-break-after: avoid;
}
.chapter h3 {
  font-family: -apple-system, sans-serif;
  font-size: 11pt;
  font-weight: 700;
  color: var(--ink);
  margin: 5mm 0 2mm 0;
  page-break-after: avoid;
}
.chapter p {
  margin-bottom: 3mm;
  text-align: justify;
  hyphens: auto;
}
.chapter p b { color: var(--php-dark); }
.chapter ul, .chapter ol { margin: 2mm 0 4mm 6mm; }
.chapter li { margin-bottom: 1.5mm; }

/* ===== CODE ===== */
.chapter pre {
  background: var(--code-bg);
  color: var(--code-fg);
  font-family: "SF Mono", Consolas, monospace;
  font-size: 8.5pt;
  line-height: 1.5;
  padding: 3mm 4mm;
  border-radius: 2mm;
  margin: 3mm 0 4mm 0;
  white-space: pre;
  overflow: hidden;
  page-break-inside: avoid;
}
.c { color: #6b8aae; font-style: italic; }
.k { color: #ff79c6; }
.s { color: #f1c40f; }
.f { color: #50fa7b; }
.t { color: #8be9fd; }
.v { color: #ffb86c; }

code.inline {
  font-family: "SF Mono", Consolas, monospace;
  font-size: 9pt;
  background: var(--bg-soft);
  padding: 0.3mm 1.5mm;
  border-radius: 1mm;
  color: var(--php-dark);
}

/* ===== CALLOUTS ===== */
.callout {
  border-radius: 2mm;
  padding: 3mm 4mm;
  margin: 4mm 0;
  font-size: 10pt;
  page-break-inside: avoid;
  display: grid;
  grid-template-columns: 6mm 1fr;
  gap: 3mm;
  align-items: start;
}
.callout-icon {
  font-family: -apple-system, sans-serif;
  font-weight: 800;
  font-size: 14pt;
  line-height: 1;
  text-align: center;
}
.callout-body > b:first-child {
  font-family: -apple-system, sans-serif;
  text-transform: uppercase;
  font-size: 8pt;
  letter-spacing: 1pt;
  display: block;
  margin-bottom: 1.5mm;
}
.callout.tip { background: #e8f4ea; border-left: 3pt solid var(--plus); }
.callout.tip .callout-icon, .callout.tip .callout-body > b:first-child { color: var(--plus); }
.callout.warn { background: #fdecea; border-left: 3pt solid var(--minus); }
.callout.warn .callout-icon, .callout.warn .callout-body > b:first-child { color: var(--minus); }
.callout.note { background: var(--bg-soft); border-left: 3pt solid var(--php); }
.callout.note .callout-icon, .callout.note .callout-body > b:first-child { color: var(--php-dark); }

/* ===== RECALL ===== */
.recall {
  background: linear-gradient(135deg, var(--php-dark) 0%, var(--php-darker) 100%);
  color: white;
  padding: 5mm 6mm;
  border-radius: 2mm;
  margin: 6mm 0 0 0;
  page-break-inside: avoid;
}
.recall b {
  font-family: -apple-system, sans-serif;
  display: block;
  text-transform: uppercase;
  letter-spacing: 1.5pt;
  font-size: 8.5pt;
  color: var(--php);
  margin-bottom: 2.5mm;
}
.recall ol {
  margin: 0;
  padding-left: 5mm;
  font-size: 10pt;
}
.recall li {
  margin-bottom: 1.5mm;
  color: rgba(255,255,255,0.95);
}
.recall li::marker { color: var(--php); font-weight: 700; }

/* ===== TABLES ===== */
.chapter table {
  width: 100%;
  border-collapse: collapse;
  margin: 3mm 0 4mm 0;
  font-size: 9.5pt;
  font-family: -apple-system, sans-serif;
}
.chapter th {
  background: var(--php-dark);
  color: white;
  padding: 2mm 3mm;
  text-align: left;
  font-weight: 700;
  font-size: 9pt;
  text-transform: uppercase;
  letter-spacing: 0.5pt;
}
.chapter td {
  padding: 2mm 3mm;
  border-bottom: 0.5pt solid var(--line);
  vertical-align: top;
}
.chapter td code {
  font-family: "SF Mono", Consolas, monospace;
  font-size: 8.5pt;
  color: var(--php-dark);
}

/* ===== ENDING ===== */
.ending { page-break-before: always; }
.ending h1 {
  font-family: -apple-system, sans-serif;
  font-size: 28pt;
  font-weight: 800;
  color: var(--php-dark);
  margin-bottom: 6mm;
  border-bottom: 2pt solid var(--php);
  padding-bottom: 3mm;
}
.ending h2 {
  font-family: -apple-system, sans-serif;
  font-size: 14pt;
  font-weight: 700;
  color: var(--php-dark);
  margin: 7mm 0 3mm 0;
}
.spaced-plan {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 3mm;
  margin: 4mm 0;
}
.spaced-day {
  background: var(--bg-soft);
  border-top: 3pt solid var(--php);
  padding: 4mm 3mm;
  border-radius: 2mm;
}
.spaced-day b {
  font-family: -apple-system, sans-serif;
  display: block;
  color: var(--php-dark);
  font-size: 9pt;
  text-transform: uppercase;
  letter-spacing: 0.5pt;
  margin-bottom: 2mm;
}
.spaced-day p {
  font-size: 9pt;
  margin: 0;
  text-align: left;
}
</style>
</head>
<body>

<!-- ===== COVER ===== -->
<section class="cover">
  <div class="cover-top">
    <div class="cover-logo">php</div>
    <div class="cover-meta">Anfänger-Guide · 2,5h · Stand 2026</div>
  </div>

  <div class="cover-main">
    <h1>PHP<br><span class="accent">in 10 Kapiteln.</span></h1>
    <p class="subtitle">Von der Installation bis zur ersten Composer-Anwendung  modern und idiomatisch.</p>
  </div>

  <div class="cover-bottom">
    <div class="cover-promise">
      <b>Was du danach kannst</b>
      PHP-Code mit Type-Hints schreiben · Arrays und Klassen modern nutzen · Funktionen sauber strukturieren · Fehler richtig behandeln · Composer-Pakete installieren und in eigenen Projekten verwenden.
    </div>
    <div class="cover-tag">PHP 8.4</div>
  </div>
</section>

<!-- ===== TOC ===== -->
<section class="toc">
  <h2>Inhalt</h2>

  <div class="toc-section">Teil 1 · Grundlagen</div>

  <div class="toc-item">
    <div class="toc-num">1</div>
    <div class="toc-text">
      <h3>PHP installieren und starten</h3>
      <p>Setup mit Docker, DDEV oder lokal, erstes Script</p>
    </div>
    <div class="toc-time">15 Min</div>
  </div>

  <div class="toc-item">
    <div class="toc-num">2</div>
    <div class="toc-text">
      <h3>Variablen und Typen</h3>
      <p>$-Variablen, strict_types, Typumwandlung</p>
    </div>
    <div class="toc-time">15 Min</div>
  </div>

  <div class="toc-item">
    <div class="toc-num">3</div>
    <div class="toc-text">
      <h3>Strings und Formatierung</h3>
      <p>Interpolation, Heredoc, String-Funktionen</p>
    </div>
    <div class="toc-time">15 Min</div>
  </div>

  <div class="toc-section">Teil 2 · Strukturen</div>

  <div class="toc-item">
    <div class="toc-num">4</div>
    <div class="toc-text">
      <h3>Arrays: Liste und Map</h3>
      <p>Indiziert, assoziativ, gemischt</p>
    </div>
    <div class="toc-time">15 Min</div>
  </div>

  <div class="toc-item">
    <div class="toc-num">5</div>
    <div class="toc-text">
      <h3>Control Flow</h3>
      <p>if, match, foreach, while</p>
    </div>
    <div class="toc-time">15 Min</div>
  </div>

  <div class="toc-item">
    <div class="toc-num">6</div>
    <div class="toc-text">
      <h3>Funktionen mit Type-Hints</h3>
      <p>Parameter, Rückgabewerte, Named Arguments</p>
    </div>
    <div class="toc-time">15 Min</div>
  </div>

  <div class="toc-section">Teil 3 · Objekte und echte Anwendungen</div>

  <div class="toc-item">
    <div class="toc-num">7</div>
    <div class="toc-text">
      <h3>Klassen und Objekte</h3>
      <p>Promoted Constructor, readonly, Methoden</p>
    </div>
    <div class="toc-time">15 Min</div>
  </div>

  <div class="toc-item">
    <div class="toc-num">8</div>
    <div class="toc-text">
      <h3>Namespaces und Autoloading</h3>
      <p>PSR-4, use-Statements, Datei-Organisation</p>
    </div>
    <div class="toc-time">15 Min</div>
  </div>

  <div class="toc-item">
    <div class="toc-num">9</div>
    <div class="toc-text">
      <h3>Fehlerbehandlung</h3>
      <p>Exceptions, try/catch, eigene Fehler</p>
    </div>
    <div class="toc-time">15 Min</div>
  </div>

  <div class="toc-item">
    <div class="toc-num">10</div>
    <div class="toc-text">
      <h3>Composer und erste Anwendung</h3>
      <p>Pakete installieren, kleines CLI-Tool bauen</p>
    </div>
    <div class="toc-time">15 Min</div>
  </div>
</section>

<!-- ===== KAPITEL 1 ===== -->
<section class="chapter">
  <div class="chapter-head">
    <div class="chapter-num">01</div>
    <div class="chapter-title">
      <h1>PHP installieren und starten</h1>
      <div class="subtitle">Setup mit Docker, DDEV oder lokal</div>
    </div>
  </div>

  <div class="gap">
    <b>Frage zum Einstieg</b>
    Du willst PHP-Code schreiben und ausführen. Aber wie kommt PHP auf deinen Rechner? Klassische XAMPP-Installation, modernes Docker, oder einfach <code>php -S</code> für schnelle Tests? Die richtige Wahl spart dir später Stunden.
  </div>

  <h2>Drei Wege, PHP zu starten</h2>
  <p>Für lokale Entwicklung gibt es drei sinnvolle Optionen, jede mit ihrem Anwendungsfall:</p>

  <table>
    <tr><th>Methode</th><th>Wann</th></tr>
    <tr><td><b>Lokal</b> (brew, apt)</td><td>Kleine Scripts, schneller Test</td></tr>
    <tr><td><b>DDEV</b></td><td>Mehrere Projekte mit DB</td></tr>
    <tr><td><b>Docker</b> direkt</td><td>Custom-Setup, CI/CD</td></tr>
  </table>

  <p>Für den Einstieg reicht eine lokale Installation. Auf macOS mit Homebrew: <code class="inline">brew install php</code>. Auf Ubuntu: <code class="inline">apt install php8.4-cli</code>. Auf Windows: am einfachsten WSL2 mit Ubuntu darin.</p>

  <h2>Erstes Script</h2>
  <p>Lege eine Datei <code class="inline">hello.php</code> an mit folgendem Inhalt:</p>

<pre><span class="t">&lt;?php</span>
<span class="k">declare</span>(strict_types=<span class="s">1</span>);

<span class="k">echo</span> <span class="s">"Hallo Welt!\n"</span>;
<span class="k">echo</span> <span class="s">"PHP-Version: "</span> . PHP_VERSION . <span class="s">"\n"</span>;</pre>

  <p>Im Terminal: <code class="inline">php hello.php</code>. Du siehst die Ausgabe. Glückwunsch  das ist alles, was PHP zum Start braucht.</p>

  <p>Die Zeile <code class="inline">declare(strict_types=1)</code> gehört in jede moderne PHP-Datei. Sie aktiviert strenge Typprüfung und verhindert, dass PHP heimlich Strings in Zahlen umwandelt. Verlässlicher Code.</p>

  <h2>Eingebauter Web-Server</h2>
  <p>Für Web-Entwicklung braucht PHP normalerweise einen Webserver (Apache, nginx). Für lokales Testen gibt es einen <b>eingebauten Server</b>:</p>

<pre><span class="c"># Im Verzeichnis mit deinen .php-Dateien</span>
php -S localhost:8000</pre>

  <p>Öffne <code class="inline">http://localhost:8000/hello.php</code> im Browser. Der Server ist nicht für Production gedacht, aber für lokale Entwicklung perfekt.</p>

  <div class="callout tip">
    <div class="callout-icon">✓</div>
    <div class="callout-body">
      <b>DDEV für echte Projekte</b>
      Sobald du eine Datenbank brauchst, mehrere Projekte gleichzeitig, oder ein konkretes PHP-Framework wie Shopware oder Laravel, lohnt sich <b>DDEV</b>  wraps Docker mit sinnvollen Defaults. <code class="inline">ddev config</code> in deinem Projektordner reicht meist.
    </div>
  </div>

  <div class="recall">
    <b>Recall</b>
    <ol>
      <li>Wie führst du eine PHP-Datei im Terminal aus?</li>
      <li>Wozu ist <code style="color:#777BB4">declare(strict_types=1)</code> gut?</li>
      <li>Wann nutzt du <code style="color:#777BB4">php -S</code>, wann DDEV?</li>
    </ol>
  </div>
</section>

<!-- ===== KAPITEL 2 ===== -->
<section class="chapter">
  <div class="chapter-head">
    <div class="chapter-num">02</div>
    <div class="chapter-title">
      <h1>Variablen und Typen</h1>
      <div class="subtitle">$-Variablen, strict_types, Typumwandlung</div>
    </div>
  </div>

  <div class="gap">
    <b>Frage zum Einstieg</b>
    PHP-Variablen beginnen mit einem <code>$</code>. Warum eigentlich? Und wie kann eine Variable mal eine Zahl, mal ein String sein, ohne dass es explodiert? Die Antwort zeigt, wie PHPs Typsystem funktioniert.
  </div>

  <h2>Variablen mit $</h2>
  <p>Jede Variable in PHP beginnt mit dem Dollar-Zeichen. Das macht sie im Code sofort erkennbar  du musst nie raten, ob ein Name eine Variable oder eine Funktion ist:</p>

<pre><span class="v">$name</span> = <span class="s">'Marek'</span>;
<span class="v">$age</span> = <span class="s">34</span>;
<span class="v">$height</span> = <span class="s">1.82</span>;
<span class="v">$isActive</span> = <span class="k">true</span>;
<span class="v">$email</span> = <span class="k">null</span>;</pre>

  <p>PHP ist <b>dynamisch typisiert</b>: derselbe Variable darf erst eine Zahl, dann ein String zugewiesen werden. Das ist flexibel, kann aber zu Bugs führen  deshalb sind Type-Hints in Funktionen so wichtig (Kapitel 6).</p>

  <h2>Die wichtigsten Typen</h2>

  <table>
    <tr><th>Typ</th><th>Beispiel</th><th>Wofür</th></tr>
    <tr><td><code>int</code></td><td><code>42</code></td><td>Ganze Zahlen</td></tr>
    <tr><td><code>float</code></td><td><code>3.14</code></td><td>Kommazahlen</td></tr>
    <tr><td><code>string</code></td><td><code>'Hi'</code></td><td>Text</td></tr>
    <tr><td><code>bool</code></td><td><code>true</code></td><td>Wahrheitswert</td></tr>
    <tr><td><code>array</code></td><td><code>[1, 2]</code></td><td>Liste oder Map</td></tr>
    <tr><td><code>null</code></td><td><code>null</code></td><td>Kein Wert</td></tr>
  </table>

  <p>Den Typ einer Variable findest du mit <code class="inline">gettype($x)</code> oder mit Funktionen wie <code class="inline">is_int($x)</code>, <code class="inline">is_string($x)</code>.</p>

  <h2>Typumwandlung</h2>
  <p>PHP wandelt Typen oft automatisch um  das ist bequem, aber tückisch. Mit explizitem Cast bist du auf der sicheren Seite:</p>

<pre><span class="v">$input</span> = <span class="s">'42'</span>;                <span class="c">// string</span>
<span class="v">$number</span> = (<span class="t">int</span>) <span class="v">$input</span>;        <span class="c">// 42 als int</span>
<span class="v">$float</span> = (<span class="t">float</span>) <span class="s">'3.14'</span>;        <span class="c">// 3.14</span>
<span class="v">$text</span> = (<span class="t">string</span>) <span class="s">42</span>;            <span class="c">// "42"</span>

<span class="c">// Boolean-Cast: 0, "", "0", null, [] sind false</span>
<span class="k">if</span> (<span class="v">$value</span>) {              <span class="c">// implizit zu bool</span>
  <span class="k">echo</span> <span class="s">'truthy'</span>;
}</pre>

  <div class="callout warn">
    <div class="callout-icon">!</div>
    <div class="callout-body">
      <b>Vergleich mit == ist tückisch</b>
      <code class="inline">'0' == false</code> ist <code class="inline">true</code>. <code class="inline">'abc' == 0</code> war in alten PHP-Versionen auch true. Nutze immer <code class="inline">===</code> für strikten Vergleich, der auch den Typ prüft.
    </div>
  </div>

  <div class="recall">
    <b>Recall</b>
    <ol>
      <li>Wie erkennst du in PHP-Code, ob etwas eine Variable ist?</li>
      <li>Was ist der Unterschied zwischen <code style="color:#777BB4">==</code> und <code style="color:#777BB4">===</code>?</li>
      <li>Welche Werte werden bei Boolean-Cast zu <code style="color:#777BB4">false</code>?</li>
    </ol>
  </div>
</section>

<!-- ===== KAPITEL 3 ===== -->
<section class="chapter">
  <div class="chapter-head">
    <div class="chapter-num">03</div>
    <div class="chapter-title">
      <h1>Strings und Formatierung</h1>
      <div class="subtitle">Interpolation, Heredoc, String-Funktionen</div>
    </div>
  </div>

  <div class="gap">
    <b>Frage zum Einstieg</b>
    In PHP gibt es einfache und doppelte Anführungszeichen für Strings. Beide funktionieren  aber sie verhalten sich unterschiedlich. Warum gibt es überhaupt zwei, und welche solltest du wann nutzen?
  </div>

  <h2>Strings: '' vs ""</h2>
  <p>Beide sind Strings, aber doppelte Anführungszeichen interpolieren Variablen, einfache nicht:</p>

<pre><span class="v">$name</span> = <span class="s">'Marek'</span>;

<span class="k">echo</span> <span class="s">"Hallo </span><span class="v">$name</span><span class="s">"</span>;       <span class="c">// Hallo Marek</span>
<span class="k">echo</span> <span class="s">'Hallo $name'</span>;       <span class="c">// Hallo $name (wörtlich)</span>

<span class="c">// Komplexere Ausdrücke: geschweifte Klammern</span>
<span class="v">$user</span> = [<span class="s">'name'</span> =&gt; <span class="s">'Marek'</span>];
<span class="k">echo</span> <span class="s">"Hallo {</span><span class="v">$user</span><span class="s">['name']}"</span>;

<span class="c">// Verkettung mit .</span>
<span class="k">echo</span> <span class="s">'Hallo '</span> . <span class="v">$name</span> . <span class="s">'!'</span>;</pre>

  <p>Faustregel: <b>Doppelte Anführungszeichen</b> wenn du Variablen einsetzen willst, <b>einfache</b> sonst. Einfache sind minimal schneller, aber das ist heute praktisch egal.</p>

  <h2>Heredoc und Nowdoc für Mehrzeiler</h2>
  <p>Für längeren Text mit Variablen oder ohne gibt es <b>Heredoc</b> und <b>Nowdoc</b>:</p>

<pre><span class="v">$name</span> = <span class="s">'Marek'</span>;

<span class="v">$mail</span> = &lt;&lt;&lt;<span class="s">TEXT</span>
<span class="s">Hallo </span><span class="v">$name</span><span class="s">,

vielen Dank für deine Bestellung.

Grüße
TEXT</span>;

<span class="c">// Nowdoc (kein Interpolation, wörtlich)</span>
<span class="v">$tpl</span> = &lt;&lt;&lt;<span class="s">'TPL'</span>
<span class="s">Verwende {{ name }} für den Namen.
TPL</span>;</pre>

  <h2>Wichtige String-Funktionen</h2>
  <p>PHP hat eine riesige Auswahl an String-Funktionen. Diese kennst du nach einer Woche auswendig:</p>

  <table>
    <tr><th>Funktion</th><th>Effekt</th></tr>
    <tr><td><code>strlen($s)</code></td><td>Länge des Strings</td></tr>
    <tr><td><code>strtoupper / strtolower</code></td><td>Groß-/Kleinschreibung</td></tr>
    <tr><td><code>trim($s)</code></td><td>Whitespace vorne/hinten entfernen</td></tr>
    <tr><td><code>str_replace($a, $b, $s)</code></td><td>a durch b ersetzen</td></tr>
    <tr><td><code>str_contains($s, $needle)</code></td><td>Prüft, ob enthalten</td></tr>
    <tr><td><code>explode(',', $s)</code></td><td>String zu Array</td></tr>
    <tr><td><code>implode(',', $arr)</code></td><td>Array zu String</td></tr>
    <tr><td><code>sprintf('%05d', 42)</code></td><td>Formatiert "00042"</td></tr>
  </table>

  <div class="callout tip">
    <div class="callout-icon">✓</div>
    <div class="callout-body">
      <b>Methoden-Verkettung mit Pipes nicht möglich</b>
      Anders als bei Objektmethoden gibt es bei String-Funktionen keine Verkettung. <code class="inline">trim(strtolower($s))</code> ist die Schreibweise  von innen nach außen lesen.
    </div>
  </div>

  <div class="recall">
    <b>Recall</b>
    <ol>
      <li>Wann nutzt du <code style="color:#777BB4">""</code>, wann <code style="color:#777BB4">''</code>?</li>
      <li>Was ist der Unterschied zwischen Heredoc und Nowdoc?</li>
      <li>Wie prüfst du, ob ein String einen anderen enthält?</li>
    </ol>
  </div>
</section>

<!-- ===== KAPITEL 4 ===== -->
<section class="chapter">
  <div class="chapter-head">
    <div class="chapter-num">04</div>
    <div class="chapter-title">
      <h1>Arrays: Liste und Map</h1>
      <div class="subtitle">Indiziert, assoziativ, gemischt</div>
    </div>
  </div>

  <div class="gap">
    <b>Frage zum Einstieg</b>
    In den meisten Sprachen sind Listen und Dictionaries zwei verschiedene Datenstrukturen. In PHP ist beides ein <code>array</code>  das macht vieles flexibel, aber auch leicht verwirrend. Wie funktioniert das?
  </div>

  <h2>Indizierte Arrays (Listen)</h2>
  <p>Eine Liste ohne explizite Keys  die Indizes werden automatisch 0, 1, 2, ...:</p>

<pre><span class="v">$fruits</span> = [<span class="s">'Apfel'</span>, <span class="s">'Birne'</span>, <span class="s">'Kirsche'</span>];

<span class="v">$fruits</span>[<span class="s">0</span>];                <span class="c">// 'Apfel'</span>
<span class="v">$fruits</span>[<span class="s">2</span>];                <span class="c">// 'Kirsche'</span>
<span class="f">count</span>(<span class="v">$fruits</span>);            <span class="c">// 3</span>

<span class="c">// Hinten anhängen</span>
<span class="v">$fruits</span>[] = <span class="s">'Banane'</span>;       <span class="c">// jetzt 4 Elemente</span>
<span class="f">array_push</span>(<span class="v">$fruits</span>, <span class="s">'Mango'</span>); <span class="c">// alternative Schreibweise</span></pre>

  <h2>Assoziative Arrays (Maps)</h2>
  <p>Mit String-Keys wird das Array zu einer Map  die häufigste Form in PHP-Code, weil viele APIs (JSON, Datenbank-Zeilen) so aussehen:</p>

<pre><span class="v">$user</span> = [
  <span class="s">'name'</span> =&gt; <span class="s">'Marek'</span>,
  <span class="s">'age'</span> =&gt; <span class="s">34</span>,
  <span class="s">'roles'</span> =&gt; [<span class="s">'admin'</span>, <span class="s">'editor'</span>],
];

<span class="v">$user</span>[<span class="s">'name'</span>];            <span class="c">// 'Marek'</span>
<span class="v">$user</span>[<span class="s">'email'</span>] = <span class="s">'m@e.de'</span>;  <span class="c">// neuer Key</span>

<span class="c">// Sicher: gibt null wenn nicht da, kein Fehler</span>
<span class="v">$phone</span> = <span class="v">$user</span>[<span class="s">'phone'</span>] ?? <span class="s">'unbekannt'</span>;</pre>

  <p>Der <b>Null-Coalescing-Operator</b> <code class="inline">??</code> ist eine der nützlichsten PHP-Features. Er gibt den linken Wert zurück, wenn er existiert und nicht null ist, sonst den rechten.</p>

  <h2>Über Arrays iterieren</h2>
  <p><code class="inline">foreach</code> ist das Werkzeug der Wahl. Es funktioniert für beide Array-Typen:</p>

<pre><span class="c">// Nur Werte</span>
<span class="k">foreach</span> (<span class="v">$fruits</span> <span class="k">as</span> <span class="v">$fruit</span>) {
  <span class="k">echo</span> <span class="v">$fruit</span>;
}

<span class="c">// Key und Wert</span>
<span class="k">foreach</span> (<span class="v">$user</span> <span class="k">as</span> <span class="v">$key</span> =&gt; <span class="v">$value</span>) {
  <span class="k">echo</span> <span class="s">"</span><span class="v">$key</span><span class="s">: </span><span class="v">$value</span><span class="s">\n"</span>;
}</pre>

  <h2>Array-Funktionen</h2>

  <table>
    <tr><th>Funktion</th><th>Wofür</th></tr>
    <tr><td><code>array_map($fn, $arr)</code></td><td>Jedes Element transformieren</td></tr>
    <tr><td><code>array_filter($arr, $fn)</code></td><td>Elemente mit Bedingung behalten</td></tr>
    <tr><td><code>array_reduce($arr, $fn, $init)</code></td><td>Aggregieren zu einem Wert</td></tr>
    <tr><td><code>array_keys / array_values</code></td><td>Keys oder Werte extrahieren</td></tr>
    <tr><td><code>in_array($x, $arr)</code></td><td>Enthält Wert?</td></tr>
    <tr><td><code>sort($arr)</code></td><td>Sortiert in-place</td></tr>
  </table>

  <div class="recall">
    <b>Recall</b>
    <ol>
      <li>Was ist der Unterschied zwischen indizierten und assoziativen Arrays?</li>
      <li>Was macht <code style="color:#777BB4">??</code> in PHP?</li>
      <li>Wie iterierst du über ein assoziatives Array mit Keys und Werten?</li>
    </ol>
  </div>
</section>

<!-- ===== KAPITEL 5 ===== -->
<section class="chapter">
  <div class="chapter-head">
    <div class="chapter-num">05</div>
    <div class="chapter-title">
      <h1>Control Flow</h1>
      <div class="subtitle">if, match, foreach, while</div>
    </div>
  </div>

  <div class="gap">
    <b>Frage zum Einstieg</b>
    Wie sagst du PHP "tu das nur, wenn X" oder "wiederhole das, bis Y"? Die klassischen Konstrukte kennst du aus jeder Sprache  aber PHP 8 hat mit <code>match</code> ein modernes Werkzeug ergänzt, das vieles eleganter macht.
  </div>

  <h2>if, elseif, else</h2>

<pre><span class="k">if</span> (<span class="v">$score</span> &gt;= <span class="s">90</span>) {
  <span class="v">$grade</span> = <span class="s">'A'</span>;
} <span class="k">elseif</span> (<span class="v">$score</span> &gt;= <span class="s">75</span>) {
  <span class="v">$grade</span> = <span class="s">'B'</span>;
} <span class="k">else</span> {
  <span class="v">$grade</span> = <span class="s">'C oder schlechter'</span>;
}

<span class="c">// Ternary für einfache Fälle</span>
<span class="v">$status</span> = <span class="v">$age</span> &gt;= <span class="s">18</span> ? <span class="s">'erwachsen'</span> : <span class="s">'minderjährig'</span>;</pre>

  <h2>match: das moderne switch</h2>
  <p>Seit PHP 8 gibt es <code class="inline">match</code>  ähnlich wie <code class="inline">switch</code>, aber strikt im Vergleich, ein Ausdruck (also mit Rückgabewert), kein fallthrough:</p>

<pre><span class="v">$status</span> = <span class="k">match</span>(<span class="v">$code</span>) {
  <span class="s">200</span>, <span class="s">201</span>, <span class="s">204</span> =&gt; <span class="s">'success'</span>,
  <span class="s">301</span>, <span class="s">302</span>       =&gt; <span class="s">'redirect'</span>,
  <span class="s">404</span>            =&gt; <span class="s">'not found'</span>,
  <span class="s">500</span>            =&gt; <span class="s">'server error'</span>,
  <span class="k">default</span>        =&gt; <span class="s">'unknown'</span>,
};</pre>

  <p>Beachte die Kommas zwischen Werten  sie bedeuten "oder". Und das <code class="inline">default</code> ist Pflicht (sonst Exception), das schützt vor vergessenen Fällen.</p>

  <h2>Schleifen</h2>

<pre><span class="c">// for: bekannte Anzahl</span>
<span class="k">for</span> (<span class="v">$i</span> = <span class="s">0</span>; <span class="v">$i</span> &lt; <span class="s">10</span>; <span class="v">$i</span>++) {
  <span class="k">echo</span> <span class="v">$i</span>;
}

<span class="c">// foreach: über Arrays</span>
<span class="k">foreach</span> (<span class="v">$items</span> <span class="k">as</span> <span class="v">$item</span>) {
  <span class="k">echo</span> <span class="v">$item</span>;
}

<span class="c">// while: unbestimmte Anzahl</span>
<span class="k">while</span> (<span class="v">$line</span> = <span class="f">fgets</span>(<span class="v">$file</span>)) {
  <span class="f">processLine</span>(<span class="v">$line</span>);
}

<span class="c">// break und continue</span>
<span class="k">foreach</span> (<span class="v">$items</span> <span class="k">as</span> <span class="v">$item</span>) {
  <span class="k">if</span> (<span class="v">$item</span>-&gt;skip) <span class="k">continue</span>;
  <span class="k">if</span> (<span class="v">$item</span>-&gt;stop) <span class="k">break</span>;
  <span class="f">process</span>(<span class="v">$item</span>);
}</pre>

  <div class="callout tip">
    <div class="callout-icon">✓</div>
    <div class="callout-body">
      <b>match statt switch</b>
      In neuem Code: nimm <code class="inline">match</code>. Strikter Vergleich (===), kein fallthrough-Fehler, Ergebnis als Wert. <code class="inline">switch</code> nur noch in Legacy-Code oder wenn du komplexe Blöcke pro Fall brauchst.
    </div>
  </div>

  <div class="recall">
    <b>Recall</b>
    <ol>
      <li>Wann nutzt du <code style="color:#777BB4">foreach</code>, wann <code style="color:#777BB4">for</code>?</li>
      <li>Was sind die wichtigsten Vorteile von <code style="color:#777BB4">match</code> gegenüber <code style="color:#777BB4">switch</code>?</li>
      <li>Was ist der Unterschied zwischen <code style="color:#777BB4">break</code> und <code style="color:#777BB4">continue</code>?</li>
    </ol>
  </div>
</section>

<!-- ===== KAPITEL 6 ===== -->
<section class="chapter">
  <div class="chapter-head">
    <div class="chapter-num">06</div>
    <div class="chapter-title">
      <h1>Funktionen mit Type-Hints</h1>
      <div class="subtitle">Parameter, Rückgabewerte, Named Arguments</div>
    </div>
  </div>

  <div class="gap">
    <b>Frage zum Einstieg</b>
    Eine Funktion ohne Type-Hints ist wie ein Brief ohne Adresse  sie kommt vielleicht an, aber niemand weiß, was sie erwartet. Modernes PHP-Code hat Types überall. Wie schreibst du sie, und was kannst du damit?
  </div>

  <h2>Funktion deklarieren</h2>

<pre><span class="k">function</span> <span class="f">add</span>(<span class="t">int</span> <span class="v">$a</span>, <span class="t">int</span> <span class="v">$b</span>): <span class="t">int</span> {
  <span class="k">return</span> <span class="v">$a</span> + <span class="v">$b</span>;
}

<span class="k">function</span> <span class="f">greet</span>(<span class="t">string</span> <span class="v">$name</span>, <span class="t">string</span> <span class="v">$greeting</span> = <span class="s">'Hallo'</span>): <span class="t">string</span> {
  <span class="k">return</span> <span class="s">"</span><span class="v">$greeting</span><span class="s">, </span><span class="v">$name</span><span class="s">!"</span>;
}

<span class="k">echo</span> <span class="f">add</span>(<span class="s">3</span>, <span class="s">4</span>);              <span class="c">// 7</span>
<span class="k">echo</span> <span class="f">greet</span>(<span class="s">'Marek'</span>);          <span class="c">// Hallo, Marek!</span></pre>

  <p>Die Syntax: <code class="inline">function name(typ $param): rückgabetyp</code>. Beides ist optional, aber heute Standard.</p>

  <h2>Named Arguments</h2>
  <p>Seit PHP 8 kannst du Argumente beim Aufruf mit Namen übergeben. Praktisch bei Funktionen mit vielen Defaults:</p>

<pre><span class="k">function</span> <span class="f">createUser</span>(
  <span class="t">string</span> <span class="v">$name</span>,
  <span class="t">int</span> <span class="v">$age</span> = <span class="s">0</span>,
  <span class="t">bool</span> <span class="v">$isAdmin</span> = <span class="k">false</span>,
  ?<span class="t">string</span> <span class="v">$email</span> = <span class="k">null</span>,
): <span class="t">User</span> { <span class="c">/* ... */</span> }

<span class="c">// Positional (alt)</span>
<span class="f">createUser</span>(<span class="s">'Marek'</span>, <span class="s">34</span>, <span class="k">false</span>, <span class="s">'m@e.de'</span>);

<span class="c">// Named (modern, lesbarer)</span>
<span class="f">createUser</span>(
  name: <span class="s">'Marek'</span>,
  email: <span class="s">'m@e.de'</span>,
  isAdmin: <span class="k">true</span>,
);</pre>

  <h2>Nullable und Union Types</h2>
  <p>Mit <code class="inline">?</code> wird ein Typ nullable, mit <code class="inline">|</code> sind mehrere Typen erlaubt:</p>

<pre><span class="c">// Darf string oder null sein</span>
<span class="k">function</span> <span class="f">find</span>(<span class="t">int</span> <span class="v">$id</span>): ?<span class="t">User</span> {
  <span class="k">return</span> <span class="v">$id</span> &gt; <span class="s">0</span> ? <span class="k">new</span> <span class="t">User</span>(<span class="v">$id</span>) : <span class="k">null</span>;
}

<span class="c">// Union: int ODER string</span>
<span class="k">function</span> <span class="f">parse</span>(<span class="t">int</span>|<span class="t">string</span> <span class="v">$input</span>): <span class="t">int</span> {
  <span class="k">return</span> (<span class="t">int</span>) <span class="v">$input</span>;
}

<span class="c">// void: gibt nichts zurück</span>
<span class="k">function</span> <span class="f">log</span>(<span class="t">string</span> <span class="v">$msg</span>): <span class="t">void</span> {
  <span class="f">file_put_contents</span>(<span class="s">'app.log'</span>, <span class="v">$msg</span>);
}</pre>

  <div class="callout warn">
    <div class="callout-icon">!</div>
    <div class="callout-body">
      <b>Closures vs. globale Variablen</b>
      Funktionen sehen <i>keine</i> Variablen aus dem umgebenden Code. Du musst sie explizit übergeben. Closures (anonyme Funktionen) können mit <code class="inline">use ($var)</code> Variablen importieren  aber Globals mit <code class="inline">global $x</code> sind tabu.
    </div>
  </div>

  <div class="recall">
    <b>Recall</b>
    <ol>
      <li>Wie deklarierst du eine Funktion, die <code style="color:#777BB4">string</code> zurückgibt?</li>
      <li>Was ist der Vorteil von Named Arguments?</li>
      <li>Was bedeutet <code style="color:#777BB4">?string</code> als Typ?</li>
    </ol>
  </div>
</section>

<!-- ===== KAPITEL 7 ===== -->
<section class="chapter">
  <div class="chapter-head">
    <div class="chapter-num">07</div>
    <div class="chapter-title">
      <h1>Klassen und Objekte</h1>
      <div class="subtitle">Promoted Constructor, readonly, Methoden</div>
    </div>
  </div>

  <div class="gap">
    <b>Frage zum Einstieg</b>
    In PHP 5 brauchten Klassen viel Boilerplate: Properties, Konstruktor, Getter, Setter  seitenweise Code für simple Daten. PHP 8 hat das drastisch reduziert. Was sieht eine moderne Klasse heute aus?
  </div>

  <h2>Klasse mit Promoted Constructor</h2>
  <p>Das wichtigste PHP-8-Feature für Klassen: Konstruktor-Parameter werden automatisch zu Properties, wenn du sie mit einem Sichtbarkeits-Modifier markierst:</p>

<pre><span class="k">class</span> <span class="t">User</span> {
  <span class="k">public function</span> <span class="f">__construct</span>(
    <span class="k">public readonly</span> <span class="t">string</span> <span class="v">$name</span>,
    <span class="k">public readonly</span> <span class="t">int</span> <span class="v">$age</span>,
    <span class="k">private</span> ?<span class="t">string</span> <span class="v">$email</span> = <span class="k">null</span>,
  ) {}

  <span class="k">public function</span> <span class="f">isAdult</span>(): <span class="t">bool</span> {
    <span class="k">return</span> <span class="v">$this</span>-&gt;age &gt;= <span class="s">18</span>;
  }

  <span class="k">public function</span> <span class="f">getEmail</span>(): ?<span class="t">string</span> {
    <span class="k">return</span> <span class="v">$this</span>-&gt;email;
  }
}

<span class="v">$user</span> = <span class="k">new</span> <span class="t">User</span>(name: <span class="s">'Marek'</span>, age: <span class="s">34</span>);
<span class="k">echo</span> <span class="v">$user</span>-&gt;name;              <span class="c">// 'Marek'</span>
<span class="k">echo</span> <span class="v">$user</span>-&gt;<span class="f">isAdult</span>() ? <span class="s">'ja'</span> : <span class="s">'nein'</span>;</pre>

  <p><code class="inline">readonly</code> verhindert nachträgliche Änderungen. <code class="inline">public</code>, <code class="inline">private</code>, <code class="inline">protected</code> steuern die Sichtbarkeit von außen.</p>

  <h2>Vererbung und Interfaces</h2>

<pre><span class="k">interface</span> <span class="t">Greetable</span> {
  <span class="k">public function</span> <span class="f">greet</span>(): <span class="t">string</span>;
}

<span class="k">class</span> <span class="t">User</span> <span class="k">implements</span> <span class="t">Greetable</span> {
  <span class="k">public function</span> <span class="f">__construct</span>(<span class="k">public readonly</span> <span class="t">string</span> <span class="v">$name</span>) {}

  <span class="k">public function</span> <span class="f">greet</span>(): <span class="t">string</span> {
    <span class="k">return</span> <span class="s">"Hallo, </span><span class="v">$this</span><span class="s">-&gt;name"</span>;
  }
}

<span class="k">class</span> <span class="t">Admin</span> <span class="k">extends</span> <span class="t">User</span> {
  <span class="k">public function</span> <span class="f">greet</span>(): <span class="t">string</span> {
    <span class="k">return</span> <span class="s">"Hallo Admin </span><span class="v">$this</span><span class="s">-&gt;name"</span>;
  }
}</pre>

  <h2>Static Methods und Konstanten</h2>

<pre><span class="k">class</span> <span class="t">Math</span> {
  <span class="k">public const</span> PI = <span class="s">3.14159</span>;

  <span class="k">public static function</span> <span class="f">square</span>(<span class="t">int</span> <span class="v">$x</span>): <span class="t">int</span> {
    <span class="k">return</span> <span class="v">$x</span> * <span class="v">$x</span>;
  }
}

<span class="k">echo</span> <span class="t">Math</span>::PI;            <span class="c">// 3.14159</span>
<span class="k">echo</span> <span class="t">Math</span>::<span class="f">square</span>(<span class="s">5</span>);     <span class="c">// 25</span></pre>

  <div class="callout note">
    <div class="callout-icon">i</div>
    <div class="callout-body">
      <b>Konstruktor-Promotion sparsam einsetzen</b>
      Bei mehr als 5-6 Parametern wird die Konstruktor-Liste unübersichtlich. Dann lieber DTOs oder Builder-Pattern. Aber für die meisten Cases mit 2-4 Properties ist Promotion ein riesiger Gewinn an Lesbarkeit.
    </div>
  </div>

  <div class="recall">
    <b>Recall</b>
    <ol>
      <li>Was generiert <code style="color:#777BB4">public readonly string $name</code> im Konstruktor?</li>
      <li>Was ist der Unterschied zwischen <code style="color:#777BB4">extends</code> und <code style="color:#777BB4">implements</code>?</li>
      <li>Wie greifst du auf eine static-Konstante zu?</li>
    </ol>
  </div>
</section>

<!-- ===== KAPITEL 8 ===== -->
<section class="chapter">
  <div class="chapter-head">
    <div class="chapter-num">08</div>
    <div class="chapter-title">
      <h1>Namespaces und Autoloading</h1>
      <div class="subtitle">PSR-4, use-Statements, Datei-Organisation</div>
    </div>
  </div>

  <div class="gap">
    <b>Frage zum Einstieg</b>
    Bei zwei Klassen mit dem Namen <code>User</code>  eine für Admins, eine für Kunden  kracht es. Wie verhindert PHP solche Konflikte? Namespaces sind die Antwort, und sie hängen eng mit Composers Autoloading zusammen.
  </div>

  <h2>Namespace deklarieren</h2>
  <p>Ein Namespace gibt deinen Klassen einen "Pfad". Konvention: ein Namespace pro Datei, am Anfang deklariert:</p>

<pre><span class="t">&lt;?php</span>
<span class="k">declare</span>(strict_types=<span class="s">1</span>);

<span class="k">namespace</span> App\Domain\User;

<span class="k">class</span> <span class="t">User</span> {
  <span class="k">public function</span> <span class="f">__construct</span>(<span class="k">public readonly</span> <span class="t">string</span> <span class="v">$name</span>) {}
}</pre>

  <p>Die volle Bezeichnung dieser Klasse ist jetzt <code class="inline">App\Domain\User\User</code>. Eine andere Klasse mit demselben Namen in einem anderen Namespace kollidiert nicht.</p>

  <h2>Klassen importieren mit use</h2>

<pre><span class="t">&lt;?php</span>
<span class="k">namespace</span> App\Controller;

<span class="k">use</span> App\Domain\User\User;
<span class="k">use</span> App\Domain\Order\Order;

<span class="k">class</span> <span class="t">UserController</span> {
  <span class="k">public function</span> <span class="f">show</span>(<span class="t">int</span> <span class="v">$id</span>): <span class="t">User</span> {
    <span class="k">return new</span> <span class="t">User</span>(<span class="s">'Marek'</span>);  <span class="c">// kein voller Pfad nötig</span>
  }
}</pre>

  <p>Mit Aliassen kannst du Namen umbenennen, wenn es Konflikte gibt:</p>

<pre><span class="k">use</span> App\Domain\User\User <span class="k">as</span> DomainUser;
<span class="k">use</span> App\Http\User <span class="k">as</span> HttpUser;</pre>

  <h2>PSR-4: Datei = Namespace</h2>
  <p><b>PSR-4</b> ist die Konvention, wie Namespaces auf Dateipfade abgebildet werden. Composer nutzt das für Autoloading. Eine typische Struktur:</p>

<pre>my-project/
├── composer.json
├── vendor/                <span class="c"># installierte Pakete</span>
└── src/
    ├── Controller/
    │   └── UserController.php   <span class="c"># App\Controller\UserController</span>
    └── Domain/
        └── User/
            └── User.php         <span class="c"># App\Domain\User\User</span></pre>

  <p>In <code class="inline">composer.json</code> definierst du das Mapping:</p>

<pre>{
  "autoload": {
    "psr-4": {
      "App\\": "src/"
    }
  }
}</pre>

  <p>Nach <code class="inline">composer dump-autoload</code> findet PHP jede Klasse anhand ihres Namespaces automatisch  kein manuelles <code class="inline">require</code> mehr.</p>

  <div class="callout tip">
    <div class="callout-icon">✓</div>
    <div class="callout-body">
      <b>Eine Klasse, eine Datei</b>
      Konvention: pro Datei genau eine Klasse, Datei-Name gleich Klassen-Name (case-sensitive!). <code class="inline">User.php</code> enthält <code class="inline">class User</code>. Die meisten Frameworks und Tools verlassen sich darauf.
    </div>
  </div>

  <div class="recall">
    <b>Recall</b>
    <ol>
      <li>Wozu sind Namespaces da?</li>
      <li>Was bedeutet PSR-4 in einem Satz?</li>
      <li>Wie importierst du eine Klasse aus einem anderen Namespace?</li>
    </ol>
  </div>
</section>

<!-- ===== KAPITEL 9 ===== -->
<section class="chapter">
  <div class="chapter-head">
    <div class="chapter-num">09</div>
    <div class="chapter-title">
      <h1>Fehlerbehandlung</h1>
      <div class="subtitle">Exceptions, try/catch, eigene Fehler</div>
    </div>
  </div>

  <div class="gap">
    <b>Frage zum Einstieg</b>
    Was passiert, wenn eine Datei nicht existiert, eine Datenbankverbindung scheitert oder eine API einen unerwarteten Wert liefert? In PHP gibt es zwei Welten: alte <code>false</code>-Rückgaben und moderne Exceptions. Wie navigierst du beide?
  </div>

  <h2>Exceptions verstehen</h2>
  <p>Eine <b>Exception</b> ist PHPs moderne Art, Fehler zu signalisieren. Wird sie nicht gefangen, bricht das Script ab. Mit <code class="inline">try/catch</code> reagierst du gezielt:</p>

<pre><span class="k">try</span> {
  <span class="v">$data</span> = <span class="f">json_decode</span>(<span class="v">$json</span>, flags: JSON_THROW_ON_ERROR);
  <span class="v">$user</span> = <span class="f">processData</span>(<span class="v">$data</span>);
} <span class="k">catch</span> (\<span class="t">JsonException</span> <span class="v">$e</span>) {
  <span class="k">echo</span> <span class="s">"Ungültiges JSON: "</span> . <span class="v">$e</span>-&gt;<span class="f">getMessage</span>();
} <span class="k">catch</span> (\<span class="t">Exception</span> <span class="v">$e</span>) {
  <span class="k">echo</span> <span class="s">"Anderer Fehler: "</span> . <span class="v">$e</span>-&gt;<span class="f">getMessage</span>();
} <span class="k">finally</span> {
  <span class="f">cleanup</span>();
}</pre>

  <p>Der <code class="inline">finally</code>-Block läuft immer  auch wenn die Exception nicht gefangen wurde. Praktisch für Cleanup wie Datei schließen oder Locks freigeben.</p>

  <h2>Mehrere Exception-Typen</h2>
  <p>PHP kennt eine ganze Hierarchie von Exception-Typen. Du kannst gezielt darauf reagieren:</p>

  <table>
    <tr><th>Exception</th><th>Wann</th></tr>
    <tr><td><code>InvalidArgumentException</code></td><td>Falsche Funktionsargumente</td></tr>
    <tr><td><code>RuntimeException</code></td><td>Fehler zur Laufzeit</td></tr>
    <tr><td><code>TypeError</code></td><td>Type-Hint verletzt</td></tr>
    <tr><td><code>ValueError</code></td><td>Wert außerhalb erlaubtem Bereich</td></tr>
    <tr><td><code>JsonException</code></td><td>JSON-Parsing fehlgeschlagen</td></tr>
    <tr><td><code>PDOException</code></td><td>Datenbankfehler</td></tr>
  </table>

  <h2>Eigene Exceptions</h2>
  <p>Für domänenspezifische Fehler definierst du eigene Exception-Klassen. Sie erben von <code class="inline">\Exception</code>:</p>

<pre><span class="k">class</span> <span class="t">InsufficientFundsException</span> <span class="k">extends</span> \<span class="t">Exception</span> {}

<span class="k">function</span> <span class="f">withdraw</span>(<span class="t">int</span> <span class="v">$amount</span>): <span class="t">void</span> {
  <span class="k">if</span> (<span class="v">$amount</span> &gt; <span class="v">$this</span>-&gt;balance) {
    <span class="k">throw new</span> <span class="t">InsufficientFundsException</span>(
      <span class="s">"Brauche </span><span class="v">$amount</span><span class="s">, habe nur </span><span class="v">$this</span><span class="s">-&gt;balance"</span>
    );
  }
  <span class="v">$this</span>-&gt;balance -= <span class="v">$amount</span>;
}</pre>

  <div class="callout warn">
    <div class="callout-icon">!</div>
    <div class="callout-body">
      <b>Niemals @-Suppression</b>
      Mit <code class="inline">@functionCall()</code> kannst du Warnings unterdrücken. Tu's nicht  du versteckst nur Probleme, die später schwer zu finden sind. Wenn du weißt, dass etwas schiefgehen kann, behandle es explizit mit try/catch.
    </div>
  </div>

  <div class="recall">
    <b>Recall</b>
    <ol>
      <li>Was passiert, wenn eine Exception nicht gefangen wird?</li>
      <li>Wann läuft der <code style="color:#777BB4">finally</code>-Block?</li>
      <li>Warum solltest du eigene Exception-Klassen schreiben?</li>
    </ol>
  </div>
</section>

<!-- ===== KAPITEL 10 ===== -->
<section class="chapter">
  <div class="chapter-head">
    <div class="chapter-num">10</div>
    <div class="chapter-title">
      <h1>Composer und erste Anwendung</h1>
      <div class="subtitle">Pakete installieren, kleines CLI-Tool bauen</div>
    </div>
  </div>

  <div class="gap">
    <b>Frage zum Einstieg</b>
    Du hast PHP gelernt  aber wie kommst du jetzt zu einem echten Projekt? <b>Composer</b> ist die Brücke: er installiert Pakete aus dem riesigen PHP-Ökosystem, lädt Klassen automatisch und gibt deinem Projekt Struktur. Lass uns ein kleines Tool bauen.
  </div>

  <h2>Projekt aufsetzen</h2>
  <p>Composer ist der Standard-Paketmanager für PHP. Installation einmal global, dann pro Projekt:</p>

<pre><span class="c"># Neues Projekt</span>
mkdir hello-cli
cd hello-cli
composer init           <span class="c"># interaktiver Wizard</span>

<span class="c"># Paket hinzufügen</span>
composer require symfony/console

<span class="c"># Projektstruktur anlegen</span>
mkdir src
mkdir bin</pre>

  <p>Composer erzeugt <code class="inline">composer.json</code> mit deinen Abhängigkeiten und den Ordner <code class="inline">vendor/</code> mit den installierten Paketen.</p>

  <h2>composer.json mit Autoload</h2>

<pre>{
  "name": "marek/hello-cli",
  "type": "project",
  "require": {
    "php": "^8.4",
    "symfony/console": "^7.0"
  },
  "autoload": {
    "psr-4": {
      "App\\": "src/"
    }
  }
}</pre>

  <p>Nach Änderungen am Autoload: <code class="inline">composer dump-autoload</code> ausführen, damit PHP die neuen Pfade kennt.</p>

  <h2>Kleines CLI-Tool bauen</h2>
  <p>Mit Symfony Console schreibst du in wenigen Zeilen ein professionelles CLI-Programm:</p>

<pre><span class="c">// src/GreetCommand.php</span>
<span class="t">&lt;?php</span>
<span class="k">namespace</span> App;

<span class="k">use</span> Symfony\Component\Console\Command\Command;
<span class="k">use</span> Symfony\Component\Console\Input\InputInterface;
<span class="k">use</span> Symfony\Component\Console\Input\InputArgument;
<span class="k">use</span> Symfony\Component\Console\Output\OutputInterface;

<span class="k">class</span> <span class="t">GreetCommand</span> <span class="k">extends</span> <span class="t">Command</span> {
  <span class="k">protected static</span> <span class="v">$defaultName</span> = <span class="s">'greet'</span>;

  <span class="k">protected function</span> <span class="f">configure</span>(): <span class="t">void</span> {
    <span class="v">$this</span>-&gt;<span class="f">addArgument</span>(<span class="s">'name'</span>, InputArgument::REQUIRED);
  }

  <span class="k">protected function</span> <span class="f">execute</span>(InputInterface <span class="v">$in</span>, OutputInterface <span class="v">$out</span>): <span class="t">int</span> {
    <span class="v">$name</span> = <span class="v">$in</span>-&gt;<span class="f">getArgument</span>(<span class="s">'name'</span>);
    <span class="v">$out</span>-&gt;<span class="f">writeln</span>(<span class="s">"&lt;info&gt;Hallo, </span><span class="v">$name</span><span class="s">!&lt;/info&gt;"</span>);
    <span class="k">return</span> Command::SUCCESS;
  }
}</pre>

<pre><span class="c">// bin/app.php</span>
<span class="t">&lt;?php</span>
<span class="k">require</span> __DIR__ . <span class="s">'/../vendor/autoload.php'</span>;

<span class="k">use</span> Symfony\Component\Console\Application;
<span class="k">use</span> App\GreetCommand;

<span class="v">$app</span> = <span class="k">new</span> Application();
<span class="v">$app</span>-&gt;<span class="f">add</span>(<span class="k">new</span> <span class="t">GreetCommand</span>());
<span class="v">$app</span>-&gt;<span class="f">run</span>();</pre>

  <p>Im Terminal: <code class="inline">php bin/app.php greet Marek</code>. Du siehst "Hallo, Marek!" in Grün. Das ist ein vollständiges CLI-Tool mit Argument-Parsing, Help-Output und Exit-Codes  mit weniger als 50 Zeilen Code.</p>

  <div class="callout tip">
    <div class="callout-icon">✓</div>
    <div class="callout-body">
      <b>Erst Tools, dann Framework</b>
      Mit Composer und einzelnen Symfony-Komponenten kommst du bei kleinen Projekten weit. Erst wenn du Routing, Templates, ORM, Auth zusammen brauchst, lohnt sich der Sprung zu einem vollen Framework wie <b>Laravel</b> oder <b>Symfony</b>.
    </div>
  </div>

  <div class="recall">
    <b>Recall</b>
    <ol>
      <li>Welche Datei steuert Composers Abhängigkeiten und Autoload?</li>
      <li>Wozu ist <code style="color:#777BB4">composer dump-autoload</code>?</li>
      <li>Welche Library nimmst du für CLI-Tools in PHP?</li>
    </ol>
  </div>
</section>

<!-- ===== ENDING ===== -->
<section class="ending">
  <h1>Wie es weitergeht</h1>

  <p>Du hast PHP jetzt in 10 Kapiteln vom ersten Script bis zur Composer-Anwendung durchlaufen. Aber Wissen verblasst ohne Wiederholung. Plane <b>aktive Wiederholung</b> ein  effektiver als jedes Re-Reading.</p>

  <h2>Spaced-Repetition-Plan</h2>
  <div class="spaced-plan">
    <div class="spaced-day">
      <b>Heute</b>
      <p>Guide gelesen, Recall-Fragen aus jedem Kapitel beantwortet.</p>
    </div>
    <div class="spaced-day">
      <b>+1 Tag</b>
      <p>OnePager überfliegen, alle Recall-Fragen aus dem Kopf beantworten.</p>
    </div>
    <div class="spaced-day">
      <b>+7 Tage</b>
      <p>Mini-Projekt: ein eigenes CLI-Tool mit Composer und Symfony Console.</p>
    </div>
    <div class="spaced-day">
      <b>+30 Tage</b>
      <p>Cheatsheet als Referenz  ein neues Paket aus Packagist einbinden.</p>
    </div>
  </div>

  <h2>Was als nächstes lernen</h2>
  <p>Mit diesen Grundlagen kannst du in jede Spezialisierung einsteigen. Empfehlungen je nach Interesse:</p>

  <ul>
    <li><b>Web-Frameworks</b>  Laravel für schnellen Einstieg, Symfony für modulare Apps</li>
    <li><b>Datenbanken</b>  PDO für SQL direkt, Doctrine als ORM für komplexe Domänen</li>
    <li><b>Testing</b>  PHPUnit für Unit-Tests, Mockery für Mocks</li>
    <li><b>Static Analysis</b>  PHPStan und Psalm finden Bugs ohne Ausführung</li>
    <li><b>E-Commerce</b>  Shopware oder Magento für Online-Shops</li>
    <li><b>CMS</b>  WordPress, Drupal oder TYPO3 für Content-Sites</li>
  </ul>

  <h2>Begleitmaterial</h2>
  <p>Dieser Guide ist Teil eines Sets:</p>
  <ul>
    <li><b>PHP OnePager</b>  die visuelle Übersicht für den Schreibtisch</li>
    <li><b>PHP Cheatsheet</b>  die dichte Referenz beim Programmieren</li>
    <li><b>PHP Mini-Guide</b>  der 15-Min-Schnelleinstieg</li>
    <li><b>PHP Anfänger-Guide</b> (dieses Dokument)  die Grundlagen tief</li>
  </ul>
</section>

</body>
</html>