143 KiB
143 KiB
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>PHP – Der Komplett-Guide</title>
<style>
/* ============================================================
PHP KOMPLETT-GUIDE · Stylesheet (WeasyPrint)
Aufbauend auf dem Mini-Guide-Stil, erweitert für Buchumfang
============================================================ */
/* ---------- PAGE ---------- */
@page {
size: A4;
margin: 20mm 18mm 18mm 18mm;
@bottom-center {
content: counter(page);
font-family: -apple-system, "Segoe UI", sans-serif;
font-size: 8pt;
color: #888;
}
@bottom-right {
content: "PHP Komplett-Guide";
font-family: -apple-system, "Segoe UI", sans-serif;
font-size: 8pt;
color: #888;
}
@top-right {
content: string(chaptertitle);
font-family: -apple-system, "Segoe UI", sans-serif;
font-size: 8pt;
color: #aaa;
}
}
/* Cover-Seite: keine Kopf-/Fußzeile */
@page cover {
margin: 0;
@bottom-center { content: none; }
@bottom-right { content: none; }
@top-right { content: none; }
}
/* Kapitel-Startseiten: keine Kopfzeile, da Titel dort prominent */
@page chapterstart {
@top-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;
--neutral: #b8860b;
}
html, body {
font-family: Charter, "Source Serif Pro", Georgia, serif;
color: var(--ink);
font-size: 10.5pt;
line-height: 1.55;
}
/* ============================================================
COVER
============================================================ */
.cover {
page: cover;
page-break-after: always;
height: 297mm;
background: linear-gradient(150deg, var(--php-darker) 0%, var(--php-dark) 45%, var(--php) 100%);
color: white;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
padding: 0 22mm;
}
.cover-logo {
width: 30mm; height: 30mm;
background: rgba(255,255,255,0.14);
border: 1.5pt solid rgba(255,255,255,0.5);
border-radius: 7mm;
display: flex; align-items: center; justify-content: center;
font-family: -apple-system, sans-serif;
font-size: 20pt; font-weight: 800;
margin-bottom: 14mm;
letter-spacing: -1pt;
}
.cover h1 {
font-family: -apple-system, sans-serif;
font-size: 42pt;
font-weight: 800;
line-height: 1.02;
letter-spacing: -1.5pt;
margin-bottom: 6mm;
}
.cover h1 .light { font-weight: 300; display:block; font-size: 30pt; opacity: 0.85; }
.cover .sub {
font-family: -apple-system, sans-serif;
font-size: 13pt;
font-weight: 400;
opacity: 0.9;
line-height: 1.5;
max-width: 130mm;
margin-bottom: 18mm;
}
.cover .meta-row {
font-family: -apple-system, sans-serif;
font-size: 9.5pt;
opacity: 0.85;
border-top: 1pt solid rgba(255,255,255,0.3);
padding-top: 5mm;
display: flex;
gap: 8mm;
}
.cover .meta-row b { font-weight: 700; }
.cover-deco {
position: absolute;
font-family: "SF Mono", Consolas, monospace;
font-size: 120pt;
font-weight: 800;
opacity: 0.06;
bottom: 10mm;
right: 12mm;
line-height: 1;
}
/* ============================================================
INHALTSVERZEICHNIS
============================================================ */
.toc {
page-break-after: always;
}
.toc h2 {
font-family: -apple-system, sans-serif;
font-size: 22pt;
font-weight: 800;
color: var(--php-dark);
margin-bottom: 8mm;
border: none;
}
.toc-part {
font-family: -apple-system, sans-serif;
font-size: 10pt;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 1.5pt;
color: var(--php);
margin: 6mm 0 2mm 0;
padding-bottom: 1mm;
border-bottom: 1pt solid var(--line);
}
.toc-part:first-of-type { margin-top: 0; }
.toc-entry {
display: flex;
font-family: -apple-system, sans-serif;
font-size: 9.5pt;
margin: 1.6mm 0;
align-items: baseline;
}
.toc-num {
color: var(--php-dark);
font-weight: 700;
width: 11mm;
flex-shrink: 0;
}
.toc-title { color: var(--ink); }
.toc-dots {
flex: 1;
border-bottom: 1pt dotted var(--line);
margin: 0 2mm;
transform: translateY(-1mm);
}
.toc-page { color: var(--muted); font-variant-numeric: tabular-nums; }
/* ============================================================
TEIL-TRENNER (Part divider)
============================================================ */
.part-divider {
page: chapterstart;
page-break-before: always;
page-break-after: always;
height: 257mm;
display: flex;
flex-direction: column;
justify-content: center;
background: var(--bg-soft);
border-radius: 4mm;
padding: 0 20mm;
}
.part-divider .part-kicker {
font-family: -apple-system, sans-serif;
font-size: 11pt;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 3pt;
color: var(--php);
margin-bottom: 4mm;
}
.part-divider h1 {
font-family: -apple-system, sans-serif;
font-size: 34pt;
font-weight: 800;
color: var(--php-darker);
letter-spacing: -1pt;
line-height: 1.05;
margin-bottom: 6mm;
}
.part-divider .part-desc {
font-size: 12pt;
color: var(--muted);
font-style: italic;
max-width: 120mm;
}
.part-divider .part-chapters {
margin-top: 10mm;
font-family: -apple-system, sans-serif;
font-size: 9.5pt;
color: var(--php-dark);
}
.part-divider .part-chapters span {
display: block;
margin: 1.5mm 0;
padding-left: 5mm;
border-left: 2pt solid var(--php);
}
/* ============================================================
KAPITEL
============================================================ */
.chapter {
page-break-before: always;
}
.chapter-head {
string-set: chaptertitle content();
margin-bottom: 6mm;
padding-bottom: 3mm;
border-bottom: 2pt solid var(--ink);
}
.chapter-num {
font-family: -apple-system, sans-serif;
font-size: 9pt;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 2pt;
color: var(--php);
display: block;
margin-bottom: 1.5mm;
}
.chapter-head h1 {
font-family: -apple-system, sans-serif;
font-size: 24pt;
font-weight: 800;
color: var(--php-dark);
letter-spacing: -0.5pt;
line-height: 1.1;
}
/* ============================================================
ÜBERSCHRIFTEN IM FLIESSTEXT
============================================================ */
h2 {
font-family: -apple-system, sans-serif;
font-size: 14pt;
font-weight: 700;
color: var(--php-dark);
margin: 6mm 0 2.5mm 0;
page-break-after: avoid;
}
h3 {
font-family: -apple-system, sans-serif;
font-size: 11pt;
font-weight: 700;
color: var(--ink);
margin: 4mm 0 1.5mm 0;
page-break-after: avoid;
}
p {
margin-bottom: 2.5mm;
text-align: justify;
hyphens: auto;
}
p b, li b { color: var(--php-dark); }
ul, ol { margin: 1.5mm 0 3mm 6mm; }
li { margin-bottom: 1mm; }
/* ============================================================
CODE
============================================================ */
pre {
background: var(--code-bg);
color: var(--code-fg);
font-family: "SF Mono", Consolas, monospace;
font-size: 8.3pt;
line-height: 1.5;
padding: 3mm 4mm;
border-radius: 2mm;
margin: 2.5mm 0 3.5mm 0;
white-space: pre;
overflow: hidden;
page-break-inside: avoid;
}
.c { color: #6b8aae; font-style: italic; } /* comment */
.k { color: #ff79c6; } /* keyword */
.s { color: #f1c40f; } /* string/number */
.f { color: #50fa7b; } /* function */
.t { color: #8be9fd; } /* tag/type */
.v { color: #ffb86c; } /* variable */
.a { color: #bd93f9; } /* attribute/annotation */
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: 2.5mm 4mm;
margin: 3mm 0;
font-size: 10pt;
page-break-inside: avoid;
display: grid;
grid-template-columns: 6mm 1fr;
gap: 3mm;
}
.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: 1mm;
}
.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); }
.callout.deep { background: #fff8e8; border-left: 3pt solid var(--neutral); }
.callout.deep .callout-icon, .callout.deep .callout-body > b:first-child { color: var(--neutral); }
/* ============================================================
TABELLEN
============================================================ */
table {
border-collapse: collapse;
width: 100%;
margin: 2.5mm 0 3.5mm 0;
font-family: -apple-system, sans-serif;
font-size: 9pt;
page-break-inside: avoid;
}
th {
background: var(--php-dark);
color: white;
text-align: left;
padding: 1.8mm 3mm;
font-weight: 700;
}
td {
padding: 1.5mm 3mm;
border-bottom: 1pt solid var(--line);
vertical-align: top;
}
tr:nth-child(even) td { background: var(--bg-soft); }
td code, th code {
font-family: "SF Mono", Consolas, monospace;
font-size: 8.2pt;
}
/* kleine Helfer */
.lead {
font-size: 11.5pt;
color: var(--muted);
font-style: italic;
margin-bottom: 4mm;
}
</style>
</head>
<body>
<section class="cover">
<div class="cover-logo">php</div>
<h1>PHP<span class="light">Der Komplett-Guide</span></h1>
<div class="sub">Von den ersten Zeilen bis zu Architektur, Patterns und Experten-Nischen. Modernes PHP 8.5 – gründlich erklärt, mit kurzem, lauffähigem Code.</div>
<div class="meta-row">
<span><b>8 Teile</b> · 46 Kapitel</span>
<span><b>PHP 8.5</b> · Stand 2026</span>
<span>Schwerpunkt: Sprache & OOP</span>
</div>
<div class="cover-deco"><?php</div>
</section><section class="toc"><h2>Inhalt</h2>
<div class="toc-part">Teil 1 · Grundlagen</div>
<div class="toc-entry"><span class="toc-num">1</span><span class="toc-title">PHP einrichten & ausführen</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">2</span><span class="toc-title">Variablen & Datentypen</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">3</span><span class="toc-title">Operatoren & Ausdrücke</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">4</span><span class="toc-title">Strings im Detail</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">5</span><span class="toc-title">Bedingungen & Verzweigungen</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">6</span><span class="toc-title">Schleifen</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">7</span><span class="toc-title">Arrays</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">8</span><span class="toc-title">Funktionen</span><span class="toc-dots"></span></div>
<div class="toc-part">Teil 2 · Struktur & Werkzeug</div>
<div class="toc-entry"><span class="toc-num">9</span><span class="toc-title">Code aufteilen: include & require</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">10</span><span class="toc-title">Fehler & Exceptions</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">11</span><span class="toc-title">Datum & Zeit</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">12</span><span class="toc-title">Dateien lesen & schreiben</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">13</span><span class="toc-title">JSON & Datenformate</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">14</span><span class="toc-title">Composer & Autoloading</span><span class="toc-dots"></span></div>
<div class="toc-part">Teil 3 · Typsystem & moderne Features</div>
<div class="toc-entry"><span class="toc-num">15</span><span class="toc-title">Typen & strict_types</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">16</span><span class="toc-title">Union-, Nullable- & spezielle Typen</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">17</span><span class="toc-title">Enums</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">18</span><span class="toc-title">Moderne Syntax-Schmankerl</span><span class="toc-dots"></span></div>
<div class="toc-part">Teil 4 · Objektorientierung</div>
<div class="toc-entry"><span class="toc-num">19</span><span class="toc-title">Klassen & Objekte</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">20</span><span class="toc-title">Sichtbarkeit & Kapselung</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">21</span><span class="toc-title">Konstruktoren modern</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">22</span><span class="toc-title">Vererbung</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">23</span><span class="toc-title">Abstrakte Klassen & Interfaces</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">24</span><span class="toc-title">Traits</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">25</span><span class="toc-title">Statisches & Konstanten</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">26</span><span class="toc-title">Magische Methoden</span><span class="toc-dots"></span></div>
<div class="toc-part">Teil 5 · Fortgeschrittene Sprache</div>
<div class="toc-entry"><span class="toc-num">27</span><span class="toc-title">Generics-Denken & Collections</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">28</span><span class="toc-title">Iteratoren & Generatoren</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">29</span><span class="toc-title">Closures & Bindung</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">30</span><span class="toc-title">Attribute</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">31</span><span class="toc-title">Reflection</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">32</span><span class="toc-title">Namespaces im Detail</span><span class="toc-dots"></span></div>
<div class="toc-part">Teil 6 · Architektur & Patterns</div>
<div class="toc-entry"><span class="toc-num">33</span><span class="toc-title">SOLID-Prinzipien</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">34</span><span class="toc-title">Dependency Injection</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">35</span><span class="toc-title">Häufige Entwurfsmuster</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">36</span><span class="toc-title">Wertobjekte & DTOs</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">37</span><span class="toc-title">Fehlerbehandlung als Architektur</span><span class="toc-dots"></span></div>
<div class="toc-part">Teil 7 · Qualität & Profi-Werkzeug</div>
<div class="toc-entry"><span class="toc-num">38</span><span class="toc-title">Testen mit PHPUnit</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">39</span><span class="toc-title">Statische Analyse</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">40</span><span class="toc-title">Code-Style & Tooling</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">41</span><span class="toc-title">Debugging & Xdebug</span><span class="toc-dots"></span></div>
<div class="toc-part">Teil 8 · Experten & Nischen</div>
<div class="toc-entry"><span class="toc-num">42</span><span class="toc-title">Performance & OPcache</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">43</span><span class="toc-title">Speicher & Referenzen</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">44</span><span class="toc-title">Prozesse, FFI & Fibers</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">45</span><span class="toc-title">CLI-Programme bauen</span><span class="toc-dots"></span></div>
<div class="toc-entry"><span class="toc-num">46</span><span class="toc-title">Sicherheit: die Klassiker</span><span class="toc-dots"></span></div>
</section>
<section class="part-divider">
<div class="part-kicker">Teil 1</div>
<h1>Grundlagen</h1>
<div class="part-desc">Vom ersten echo bis zu Arrays, Schleifen und eigenen Funktionen. Alles, was du brauchst, um echte kleine Programme zu schreiben.</div>
<div class="part-chapters"><span>1 · PHP einrichten & ausführen</span><span>2 · Variablen & Datentypen</span><span>3 · Operatoren & Ausdrücke</span><span>4 · Strings im Detail</span><span>5 · Bedingungen & Verzweigungen</span><span>6 · Schleifen</span><span>7 · Arrays</span><span>8 · Funktionen</span></div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 1</span>
<h1>PHP einrichten & ausführen</h1>
</div>
<p class="lead">PHP ist eine Skriptsprache, die Code in Ausgaben verwandelt – Text, HTML, JSON. Sie läuft auf deinem Rechner und auf Webservern. Bevor wir programmieren, brauchst du eine lauffähige Installation.</p>
<h2>Installation</h2>
<p>PHP ist auf jedem Betriebssystem mit wenigen Befehlen installiert. Die aktuelle stabile Version ist <b>PHP 8.5</b> (Stand 2026); für neue Projekte ist das die richtige Wahl, <b>PHP 8.4</b> der konservative Fallback.</p>
<table>
<tr><th>System</th><th>Befehl</th></tr>
<tr><td>macOS (Homebrew)</td><td><code>brew install php</code></td></tr>
<tr><td>Ubuntu / Debian</td><td><code>sudo apt install php-cli</code></td></tr>
<tr><td>Fedora</td><td><code>sudo dnf install php-cli</code></td></tr>
<tr><td>Windows</td><td>WSL2 + Ubuntu, dann <code>apt install php-cli</code></td></tr>
</table>
<p>Prüfe danach im Terminal, ob alles läuft:</p>
<pre>php --version
<span class="c"># PHP 8.5.6 (cli) ...</span></pre>
<h2>Die erste Datei</h2>
<p>PHP-Code lebt in Dateien mit der Endung <code class="inline">.php</code>. Lege <code class="inline">hallo.php</code> an:</p>
<pre><span class="t"><?php</span>
<span class="k">echo</span> <span class="s">"Hallo Welt!"</span>;</pre>
<p>Die Zeile <code class="inline"><?php</code> öffnet einen PHP-Block. <code class="inline">echo</code> gibt Text aus. Der Text steht in Anführungszeichen und heißt <b>String</b>. Jede Anweisung endet mit einem <b>Semikolon</b>.</p>
<p>Ausführen:</p>
<pre>php hallo.php
<span class="c"># Hallo Welt!</span></pre>
<h2>Der eingebaute Webserver</h2>
<p>PHP bringt einen Entwicklungs-Webserver mit. Damit testest du Web-Code ohne Apache oder Nginx:</p>
<pre>php -S localhost:8000</pre>
<p>Öffne <code class="inline">http://localhost:8000</code> im Browser. Jede <code class="inline">.php</code>-Datei im Ordner wird nun ausgeführt und das Ergebnis ausgeliefert.</p>
<h2>PHP eingebettet in HTML</h2>
<p>PHP wurde fürs Web erfunden. Du kannst PHP-Blöcke direkt in HTML einstreuen. Alles außerhalb von <code class="inline"><?php ... ?></code> wird unverändert ausgegeben:</p>
<pre><span class="t"><h1></span>Meine Seite<span class="t"></h1></span>
<span class="t"><?php</span> <span class="k">echo</span> <span class="s">"Heute ist "</span> . <span class="k">date</span>(<span class="s">"d.m.Y"</span>); <span class="t">?></span></pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Reine PHP-Dateien</b>In Dateien, die <b>nur</b> PHP enthalten (z. B. Klassen), lässt man das schließende <code class="inline">?></code> bewusst weg. Das verhindert versehentliche Leerzeichen in der Ausgabe – ein verbreiteter Standard (PSR-12).</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 2</span>
<h1>Variablen & Datentypen</h1>
</div>
<p class="lead">Eine Variable ist ein benannter Speicherplatz für einen Wert – wie eine beschriftete Box. In PHP beginnen Variablennamen immer mit einem Dollar-Zeichen.</p>
<h2>Zuweisung</h2>
<pre><span class="v">$name</span> = <span class="s">"Marek"</span>;
<span class="v">$alter</span> = <span class="s">34</span>;
<span class="v">$groesse</span> = <span class="s">1.82</span>;
<span class="v">$istAktiv</span> = <span class="k">true</span>;</pre>
<p>Das einfache <code class="inline">=</code> bedeutet nicht „ist gleich", sondern „speichere den rechten Wert links". Das nennt man <b>Zuweisung</b>. Variablennamen sind frei wählbar, beginnen mit Buchstabe oder Unterstrich und sind <b>case-sensitive</b>: <code class="inline">$name</code> und <code class="inline">$Name</code> sind verschieden.</p>
<h2>Die wichtigsten Datentypen</h2>
<table>
<tr><th>Typ</th><th>Bedeutung</th><th>Beispiel</th></tr>
<tr><td><code>string</code></td><td>Text</td><td><code>"Hallo"</code></td></tr>
<tr><td><code>int</code></td><td>Ganzzahl</td><td><code>42</code></td></tr>
<tr><td><code>float</code></td><td>Kommazahl</td><td><code>3.14</code></td></tr>
<tr><td><code>bool</code></td><td>Wahrheitswert</td><td><code>true</code> / <code>false</code></td></tr>
<tr><td><code>array</code></td><td>Liste von Werten</td><td><code>[1, 2, 3]</code></td></tr>
<tr><td><code>null</code></td><td>„kein Wert"</td><td><code>null</code></td></tr>
</table>
<h2>Typ herausfinden</h2>
<p>PHP ist <b>dynamisch typisiert</b>: Eine Variable kann ihren Typ wechseln. Mit <code class="inline">gettype()</code> oder <code class="inline">var_dump()</code> siehst du, was drinsteckt:</p>
<pre><span class="v">$x</span> = <span class="s">42</span>;
<span class="k">var_dump</span>(<span class="v">$x</span>); <span class="c">// int(42)</span>
<span class="v">$x</span> = <span class="s">"jetzt Text"</span>;
<span class="k">var_dump</span>(<span class="v">$x</span>); <span class="c">// string(10) "jetzt Text"</span></pre>
<h2>Konstanten</h2>
<p>Werte, die sich nie ändern, speicherst du in <b>Konstanten</b>. Sie haben kein <code class="inline">$</code> und werden traditionell GROSS geschrieben:</p>
<pre><span class="k">const</span> <span class="v">MWST</span> = <span class="s">0.19</span>;
<span class="k">echo</span> <span class="v">MWST</span>; <span class="c">// 0.19</span></pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Das Dollar-Zeichen</b>Das <code class=”inline">$</code> vor jeder Variable ist eine PHP-Besonderheit. Es erlaubt dem Interpreter, Variablen sofort von Schlüsselwörtern wie <code class="inline">echo</code> zu unterscheiden, und macht sie in eingebettetem HTML klar erkennbar.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 3</span>
<h1>Operatoren & Ausdrücke</h1>
</div>
<p class="lead">Operatoren verknüpfen Werte zu neuen Werten. Sie sind das Handwerkszeug für jede Berechnung und jeden Vergleich.</p>
<h2>Arithmetik</h2>
<pre><span class="k">echo</span> <span class="s">7</span> + <span class="s">3</span>; <span class="c">// 10</span>
<span class="k">echo</span> <span class="s">7</span> - <span class="s">3</span>; <span class="c">// 4</span>
<span class="k">echo</span> <span class="s">7</span> * <span class="s">3</span>; <span class="c">// 21</span>
<span class="k">echo</span> <span class="s">7</span> / <span class="s">2</span>; <span class="c">// 3.5</span>
<span class="k">echo</span> <span class="s">7</span> % <span class="s">3</span>; <span class="c">// 1 (Rest der Division)</span>
<span class="k">echo</span> <span class="s">2</span> ** <span class="s">8</span>; <span class="c">// 256 (Potenz)</span></pre>
<h2>Zuweisungs-Kurzformen</h2>
<p>Statt <code class="inline">$x = $x + 5</code> schreibt man kürzer:</p>
<pre><span class="v">$x</span> += <span class="s">5</span>; <span class="c">// erhöhen um 5</span>
<span class="v">$x</span> -= <span class="s">2</span>; <span class="c">// verringern um 2</span>
<span class="v">$x</span> *= <span class="s">3</span>; <span class="c">// multiplizieren</span>
<span class="v">$x</span>++; <span class="c">// um 1 erhöhen</span>
<span class="v">$x</span>--; <span class="c">// um 1 verringern</span></pre>
<h2>Vergleiche</h2>
<table>
<tr><th>Operator</th><th>Bedeutung</th></tr>
<tr><td><code>==</code></td><td>gleich (Wert)</td></tr>
<tr><td><code>===</code></td><td>gleich (Wert <b>und</b> Typ)</td></tr>
<tr><td><code>!=</code> / <code>!==</code></td><td>ungleich / streng ungleich</td></tr>
<tr><td><code><</code> <code>></code> <code><=</code> <code>>=</code></td><td>kleiner, größer, …</td></tr>
<tr><td><code><=></code></td><td>Spaceship: -1, 0 oder 1</td></tr>
</table>
<h2>Logik</h2>
<pre><span class="v">$a</span> = <span class="k">true</span>; <span class="v">$b</span> = <span class="k">false</span>;
<span class="k">var_dump</span>(<span class="v">$a</span> && <span class="v">$b</span>); <span class="c">// false (und)</span>
<span class="k">var_dump</span>(<span class="v">$a</span> || <span class="v">$b</span>); <span class="c">// true (oder)</span>
<span class="k">var_dump</span>(!<span class="v">$a</span>); <span class="c">// false (nicht)</span></pre>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>== gegen ===</b><code class="inline">==</code> vergleicht nur den Wert und wandelt Typen vorher um: <code class="inline">0 == "text"</code> kann überraschende Ergebnisse liefern. <code class="inline">===</code> prüft Wert <b>und</b> Typ und ist fast immer die sichere Wahl. Gewöhne dir <code class="inline">===</code> als Standard an.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 4</span>
<h1>Strings im Detail</h1>
</div>
<p class="lead">Text ist allgegenwärtig. PHP bietet viele Wege, Strings zu bauen, zu kombinieren und zu durchsuchen.</p>
<h2>Anführungszeichen: einfach vs. doppelt</h2>
<p>In <b>doppelten</b> Anführungszeichen werden Variablen direkt eingesetzt (Interpolation). In <b>einfachen</b> nicht:</p>
<pre><span class="v">$name</span> = <span class="s">"Anna"</span>;
<span class="k">echo</span> <span class="s">"Hallo $name"</span>; <span class="c">// Hallo Anna</span>
<span class="k">echo</span> <span class="s">'Hallo $name'</span>; <span class="c">// Hallo $name</span></pre>
<p>Bei zusammengesetzten Ausdrücken nutzt du geschweifte Klammern zur Abgrenzung:</p>
<pre><span class="k">echo</span> <span class="s">"Summe: {</span><span class="v">$preis</span><span class="s"> €}"</span>;</pre>
<h2>Verketten</h2>
<p>Der Punkt-Operator klebt Strings zusammen:</p>
<pre><span class="v">$gruss</span> = <span class="s">"Hallo, "</span> . <span class="v">$name</span> . <span class="s">"!"</span>;</pre>
<h2>Nützliche String-Funktionen</h2>
<table>
<tr><th>Funktion</th><th>Zweck</th></tr>
<tr><td><code>strlen($s)</code></td><td>Länge in Bytes</td></tr>
<tr><td><code>mb_strlen($s)</code></td><td>Länge in Zeichen (Umlaute!)</td></tr>
<tr><td><code>strtoupper / strtolower</code></td><td>Groß-/Kleinschreibung</td></tr>
<tr><td><code>trim($s)</code></td><td>Leerzeichen am Rand entfernen</td></tr>
<tr><td><code>str_replace(a, b, $s)</code></td><td>ersetzen</td></tr>
<tr><td><code>str_contains($s, $t)</code></td><td>enthält? (bool)</td></tr>
<tr><td><code>explode(",", $s)</code></td><td>String → Array</td></tr>
<tr><td><code>implode(",", $arr)</code></td><td>Array → String</td></tr>
</table>
<pre><span class="v">$mail</span> = <span class="s">" Marek@example.com "</span>;
<span class="k">echo</span> <span class="k">strtolower</span>(<span class="k">trim</span>(<span class="v">$mail</span>));
<span class="c">// marek@example.com</span></pre>
<h2>printf & sprintf</h2>
<p>Für formatierte Ausgaben mit Platzhaltern:</p>
<pre><span class="k">printf</span>(<span class="s">"%s ist %d Jahre alt.\n"</span>, <span class="v">$name</span>, <span class="v">$alter</span>);
<span class="v">$preis</span> = <span class="k">sprintf</span>(<span class="s">"%.2f €"</span>, <span class="s">3.5</span>); <span class="c">// "3.50 €"</span></pre>
<h2>Heredoc für lange Texte</h2>
<pre><span class="v">$html</span> = <span class="t"><<<HTML</span>
<span class="s"><h1>$name</h1></span>
<span class="s"><p>Willkommen!</p></span>
<span class="t">HTML</span>;</pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>mb_-Funktionen bei Umlauten</b>Bei Texten mit Umlauten oder Emojis nutze die <code class="inline">mb_*</code>-Varianten (Multibyte). <code class="inline">strlen("Größe")</code> zählt Bytes, <code class="inline">mb_strlen("Größe")</code> zählt Zeichen – das willst du fast immer.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 5</span>
<h1>Bedingungen & Verzweigungen</h1>
</div>
<p class="lead">Programme entscheiden: „Wenn X, dann Y, sonst Z." Verzweigungen steuern, welcher Code unter welchen Umständen läuft.</p>
<h2>if / elseif / else</h2>
<pre><span class="v">$punkte</span> = <span class="s">75</span>;
<span class="k">if</span> (<span class="v">$punkte</span> >= <span class="s">90</span>) {
<span class="k">echo</span> <span class="s">"Sehr gut"</span>;
} <span class="k">elseif</span> (<span class="v">$punkte</span> >= <span class="s">50</span>) {
<span class="k">echo</span> <span class="s">"Bestanden"</span>;
} <span class="k">else</span> {
<span class="k">echo</span> <span class="s">"Durchgefallen"</span>;
}</pre>
<p>Die Bedingung in der Klammer muss einen Wahrheitswert ergeben. Der erste zutreffende Block läuft, der Rest wird übersprungen.</p>
<h2>match – die moderne Alternative</h2>
<p>Seit PHP 8 gibt es <code class="inline">match</code>: kompakt, typsicher (<code class="inline">===</code>) und es <b>liefert einen Wert zurück</b>:</p>
<pre><span class="v">$tag</span> = <span class="s">3</span>;
<span class="v">$name</span> = <span class="k">match</span>(<span class="v">$tag</span>) {
<span class="s">1</span>, <span class="s">2</span>, <span class="s">3</span>, <span class="s">4</span>, <span class="s">5</span> => <span class="s">"Werktag"</span>,
<span class="s">6</span>, <span class="s">7</span> => <span class="s">"Wochenende"</span>,
<span class="k">default</span> => <span class="s">"ungültig"</span>,
};</pre>
<h2>Der ternäre Operator</h2>
<p>Eine kurze if/else-Form für einfache Fälle:</p>
<pre><span class="v">$status</span> = <span class="v">$alter</span> >= <span class="s">18</span> ? <span class="s">"erwachsen"</span> : <span class="s">"minderjährig"</span>;</pre>
<h2>Null-Coalescing</h2>
<p>Liefert den ersten Wert, der existiert und nicht <code class="inline">null</code> ist – praktisch für Standardwerte:</p>
<pre><span class="v">$name</span> = <span class="v">$_GET</span>[<span class="s">'name'</span>] ?? <span class="s">"Gast"</span>;</pre>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>= statt == in Bedingungen</b>Ein einzelnes <code class=”inline">=</code> in einer Bedingung <b>speichert</b> einen Wert, statt ihn zu prüfen – und ergibt fast immer „wahr”. Das ist ein klassischer Anfängerfehler. In Bedingungen gehören mindestens zwei Gleichheitszeichen.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 6</span>
<h1>Schleifen</h1>
</div>
<p class="lead">Schleifen wiederholen Code, bis eine Bedingung erfüllt ist. Sie ersparen dir, dieselbe Anweisung hundertmal zu tippen.</p>
<h2>while – solange etwas gilt</h2>
<pre><span class="v">$i</span> = <span class="s">1</span>;
<span class="k">while</span> (<span class="v">$i</span> <= <span class="s">3</span>) {
<span class="k">echo</span> <span class="v">$i</span>; <span class="c">// 123</span>
<span class="v">$i</span>++;
}</pre>
<h2>for – feste Anzahl</h2>
<p>Drei Teile in einer Zeile: Start, Bedingung, Schritt.</p>
<pre><span class="k">for</span> (<span class="v">$i</span> = <span class="s">0</span>; <span class="v">$i</span> < <span class="s">5</span>; <span class="v">$i</span>++) {
<span class="k">echo</span> <span class="v">$i</span>; <span class="c">// 01234</span>
}</pre>
<h2>foreach – über Listen</h2>
<p>Die wichtigste Schleife in der Praxis: Sie geht jedes Element eines Arrays durch.</p>
<pre><span class="v">$obst</span> = [<span class="s">"Apfel"</span>, <span class="s">"Birne"</span>, <span class="s">"Kirsche"</span>];
<span class="k">foreach</span> (<span class="v">$obst</span> <span class="k">as</span> <span class="v">$frucht</span>) {
<span class="k">echo</span> <span class="v">$frucht</span> . <span class="s">"\n"</span>;
}</pre>
<p>Mit Schlüssel und Wert zugleich:</p>
<pre><span class="k">foreach</span> (<span class="v">$preise</span> <span class="k">as</span> <span class="v">$produkt</span> => <span class="v">$preis</span>) {
<span class="k">echo</span> <span class="s">"$produkt: $preis €\n"</span>;
}</pre>
<h2>break & continue</h2>
<p><code class="inline">break</code> bricht die Schleife ganz ab, <code class="inline">continue</code> springt zum nächsten Durchlauf:</p>
<pre><span class="k">foreach</span> (<span class="v">$zahlen</span> <span class="k">as</span> <span class="v">$z</span>) {
<span class="k">if</span> (<span class="v">$z</span> < <span class="s">0</span>) <span class="k">continue</span>; <span class="c">// negative überspringen</span>
<span class="k">if</span> (<span class="v">$z</span> > <span class="s">100</span>) <span class="k">break</span>; <span class="c">// ab 100 aufhören</span>
<span class="k">echo</span> <span class="v">$z</span>;
}</pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>foreach ist dein Standard</b>In der Praxis ist <code class="inline">foreach</code> die mit Abstand häufigste Schleife. <code class="inline">for</code> brauchst du nur, wenn du den Zähler selbst kontrollieren musst; <code class="inline">while</code>, wenn die Anzahl der Durchläufe vorher unbekannt ist.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 7</span>
<h1>Arrays</h1>
</div>
<p class="lead">Ein Array speichert mehrere Werte unter einem Namen. In PHP ist es extrem flexibel: Liste, Schlüssel-Wert-Sammlung und Verschachtelung in einem.</p>
<h2>Indizierte Arrays</h2>
<p>Werte mit automatischen Nummern (beginnend bei 0):</p>
<pre><span class="v">$farben</span> = [<span class="s">"rot"</span>, <span class="s">"grün"</span>, <span class="s">"blau"</span>];
<span class="k">echo</span> <span class="v">$farben</span>[<span class="s">0</span>]; <span class="c">// rot</span>
<span class="v">$farben</span>[] = <span class="s">"gelb"</span>; <span class="c">// anhängen</span></pre>
<h2>Assoziative Arrays</h2>
<p>Werte mit eigenen Schlüsseln – ideal für strukturierte Daten:</p>
<pre><span class="v">$person</span> = [
<span class="s">"name"</span> => <span class="s">"Marek"</span>,
<span class="s">"alter"</span> => <span class="s">34</span>,
<span class="s">"stadt"</span> => <span class="s">"Kaltenkirchen"</span>,
];
<span class="k">echo</span> <span class="v">$person</span>[<span class="s">"name"</span>]; <span class="c">// Marek</span></pre>
<h2>Verschachtelung</h2>
<pre><span class="v">$team</span> = [
[<span class="s">"name"</span> => <span class="s">"Anna"</span>, <span class="s">"rolle"</span> => <span class="s">"Dev"</span>],
[<span class="s">"name"</span> => <span class="s">"Ben"</span>, <span class="s">"rolle"</span> => <span class="s">"Design"</span>],
];
<span class="k">echo</span> <span class="v">$team</span>[<span class="s">0</span>][<span class="s">"name"</span>]; <span class="c">// Anna</span></pre>
<h2>Wichtige Array-Funktionen</h2>
<table>
<tr><th>Funktion</th><th>Zweck</th></tr>
<tr><td><code>count($a)</code></td><td>Anzahl Elemente</td></tr>
<tr><td><code>in_array($x, $a)</code></td><td>enthält Wert?</td></tr>
<tr><td><code>array_keys / array_values</code></td><td>Schlüssel / Werte</td></tr>
<tr><td><code>sort / rsort</code></td><td>auf-/absteigend sortieren</td></tr>
<tr><td><code>array_map</code></td><td>jeden Wert transformieren</td></tr>
<tr><td><code>array_filter</code></td><td>Werte herausfiltern</td></tr>
<tr><td><code>array_merge</code></td><td>Arrays zusammenfügen</td></tr>
</table>
<pre><span class="v">$zahlen</span> = [<span class="s">1</span>, <span class="s">2</span>, <span class="s">3</span>, <span class="s">4</span>];
<span class="v">$quadrate</span> = <span class="k">array_map</span>(<span class="k">fn</span>(<span class="v">$n</span>) => <span class="v">$n</span> ** <span class="s">2</span>, <span class="v">$zahlen</span>);
<span class="c">// [1, 4, 9, 16]</span>
<span class="v">$gerade</span> = <span class="k">array_filter</span>(<span class="v">$zahlen</span>, <span class="k">fn</span>(<span class="v">$n</span>) => <span class="v">$n</span> % <span class="s">2</span> === <span class="s">0</span>);
<span class="c">// [2, 4]</span></pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Ein Typ, viele Rollen</b>In vielen Sprachen sind Liste und Wörterbuch getrennte Typen. PHP hat nur <b>einen</b> Array-Typ, der beides kann. Das ist praktisch, aber sei dir bewusst, ob deine Schlüssel Zahlen oder Strings sind – das beeinflusst Sortierung und Iteration.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 8</span>
<h1>Funktionen</h1>
</div>
<p class="lead">Eine Funktion bündelt Code, den du benennen und wiederverwenden kannst. Sie nimmt Eingaben (Parameter) und liefert oft ein Ergebnis (Rückgabewert).</p>
<h2>Definition & Aufruf</h2>
<pre><span class="k">function</span> <span class="f">begruessen</span>(<span class="v">$name</span>) {
<span class="k">echo</span> <span class="s">"Hallo, $name!\n"</span>;
}
<span class="f">begruessen</span>(<span class="s">"Marek"</span>);
<span class="f">begruessen</span>(<span class="s">"Anna"</span>);</pre>
<h2>Rückgabewerte</h2>
<p><code class="inline">return</code> beendet die Funktion und liefert einen Wert an den Aufrufer zurück:</p>
<pre><span class="k">function</span> <span class="f">addiere</span>(<span class="v">$a</span>, <span class="v">$b</span>) {
<span class="k">return</span> <span class="v">$a</span> + <span class="v">$b</span>;
}
<span class="v">$summe</span> = <span class="f">addiere</span>(<span class="s">3</span>, <span class="s">5</span>); <span class="c">// 8</span></pre>
<p>Unterschied: <code class="inline">echo</code> gibt etwas auf dem Bildschirm aus, <code class="inline">return</code> gibt einen Wert zurück, mit dem du weiterrechnen kannst.</p>
<h2>Typdeklarationen</h2>
<p>Modernes PHP gibt Parametern und Rückgabe feste Typen. Das macht Code sicherer und selbsterklärend:</p>
<pre><span class="k">function</span> <span class="f">addiere</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>;
}</pre>
<h2>Standardwerte & benannte Argumente</h2>
<pre><span class="k">function</span> <span class="f">verbinde</span>(<span class="t">string</span> <span class="v">$host</span>, <span class="t">int</span> <span class="v">$port</span> = <span class="s">5432</span>): <span class="t">string</span> {
<span class="k">return</span> <span class="s">"$host:$port"</span>;
}
<span class="f">verbinde</span>(<span class="s">"db.local"</span>); <span class="c">// db.local:5432</span>
<span class="f">verbinde</span>(<span class="s">"db.local"</span>, port: <span class="s">5433</span>); <span class="c">// benanntes Argument</span></pre>
<h2>Anonyme Funktionen & Arrow Functions</h2>
<p>Funktionen ohne Namen, oft als Argument für andere Funktionen:</p>
<pre><span class="v">$verdopple</span> = <span class="k">fn</span>(<span class="v">$x</span>) => <span class="v">$x</span> * <span class="s">2</span>;
<span class="k">echo</span> <span class="v">$verdopple</span>(<span class="s">21</span>); <span class="c">// 42</span></pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Typen von Anfang an</b>Auch wenn PHP Typen nicht erzwingt: Schreib sie hin. Typdeklarationen fangen Fehler früh ab, dokumentieren deine Absicht und sind die Grundlage für gute Editor-Unterstützung. Wir vertiefen das in Teil 3.</div>
</div>
</section>
<section class="part-divider">
<div class="part-kicker">Teil 2</div>
<h1>Struktur & Werkzeug</h1>
<div class="part-desc">Code auf mehrere Dateien verteilen, Fehler sauber behandeln, mit Datum, Dateien und JSON arbeiten – und Composer als Paketmanager nutzen.</div>
<div class="part-chapters"><span>9 · Code aufteilen: include & require</span><span>10 · Fehler & Exceptions</span><span>11 · Datum & Zeit</span><span>12 · Dateien lesen & schreiben</span><span>13 · JSON & Datenformate</span><span>14 · Composer & Autoloading</span></div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 9</span>
<h1>Code aufteilen: include & require</h1>
</div>
<p class="lead">Sobald ein Programm wächst, willst du es auf mehrere Dateien verteilen – nach Themen geordnet. PHP bindet Dateien mit vier Schlüsselwörtern ein.</p>
<h2>include und require</h2>
<p>Beide fügen den Inhalt einer anderen Datei an dieser Stelle ein. Der Unterschied liegt im Fehlerfall:</p>
<table>
<tr><th>Befehl</th><th>Wenn Datei fehlt</th></tr>
<tr><td><code>include</code></td><td>Warnung, Programm läuft weiter</td></tr>
<tr><td><code>require</code></td><td>fataler Fehler, Programm stoppt</td></tr>
<tr><td><code>include_once</code> / <code>require_once</code></td><td>bindet nur einmal ein</td></tr>
</table>
<pre><span class="c">// funktionen.php</span>
<span class="k">function</span> <span class="f">gruss</span>(<span class="v">$n</span>) { <span class="k">return</span> <span class="s">"Hi $n"</span>; }
<span class="c">// app.php</span>
<span class="k">require_once</span> <span class="s">"funktionen.php"</span>;
<span class="k">echo</span> <span class="f">gruss</span>(<span class="s">"Marek"</span>);</pre>
<h2>Warum _once?</h2>
<p>Bindest du dieselbe Datei zweimal ein, würde eine Funktion doppelt definiert – das ist ein Fehler. <code class="inline">require_once</code> merkt sich, was schon geladen wurde, und verhindert das.</p>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>In der Praxis: Autoloading</b>Heute bindet man Dateien selten von Hand ein. Composer (Kapitel 14) lädt Klassen automatisch, sobald sie gebraucht werden. <code class="inline">require</code> sieht man vor allem noch für den zentralen <code class="inline">autoload.php</code>-Einstieg.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 10</span>
<h1>Fehler & Exceptions</h1>
</div>
<p class="lead">Fehler passieren: eine Datei fehlt, eine Eingabe ist ungültig, ein Server antwortet nicht. Exceptions sind PHPs strukturierter Weg, damit umzugehen.</p>
<h2>try / catch</h2>
<p>Du umschließt riskanten Code mit <code class="inline">try</code>. Tritt ein Fehler auf, springt PHP in den passenden <code class="inline">catch</code>-Block – das Programm stürzt nicht ab:</p>
<pre><span class="k">try</span> {
<span class="v">$wert</span> = <span class="s">10</span> / <span class="v">$teiler</span>;
} <span class="k">catch</span> (<span class="t">DivisionByZeroError</span> <span class="v">$e</span>) {
<span class="k">echo</span> <span class="s">"Division durch Null!"</span>;
}</pre>
<h2>Eigene Exceptions werfen</h2>
<p>Mit <code class="inline">throw</code> löst du selbst einen Fehler aus, wenn etwas nicht stimmt:</p>
<pre><span class="k">function</span> <span class="f">alterPruefen</span>(<span class="t">int</span> <span class="v">$alter</span>): <span class="t">void</span> {
<span class="k">if</span> (<span class="v">$alter</span> < <span class="s">0</span>) {
<span class="k">throw new</span> <span class="t">InvalidArgumentException</span>(<span class="s">"Alter negativ"</span>);
}
}</pre>
<h2>finally</h2>
<p>Der <code class="inline">finally</code>-Block läuft immer – egal ob ein Fehler auftrat. Ideal zum Aufräumen:</p>
<pre><span class="k">try</span> {
<span class="v">$datei</span> = <span class="k">fopen</span>(<span class="s">"log.txt"</span>, <span class="s">"a"</span>);
<span class="c">// ... schreiben ...</span>
} <span class="k">finally</span> {
<span class="k">fclose</span>(<span class="v">$datei</span>); <span class="c">// immer schließen</span>
}</pre>
<h2>Die Exception-Hierarchie</h2>
<p>Alle Fehlerklassen erben von <code class="inline">Throwable</code>. Wichtig zu wissen:</p>
<ul>
<li><code class="inline">Exception</code> – „normale" Fehler, die man abfangen sollte</li>
<li><code class="inline">Error</code> – schwere PHP-Fehler (Typfehler, fehlende Funktion)</li>
<li>Spezialisierte Klassen wie <code class="inline">RuntimeException</code>, <code class="inline">LogicException</code></li>
</ul>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>Nicht alles wegfangen</b>Ein leeres <code class=”inline">catch</code>, das Fehler verschluckt, ist gefährlich – du merkst nie, dass etwas schiefging. Fange nur Fehler ab, auf die du sinnvoll reagieren kannst, und logge oder melde den Rest.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 11</span>
<h1>Datum & Zeit</h1>
</div>
<p class="lead">Mit Datum und Zeit zu rechnen ist erstaunlich fehleranfällig – Zeitzonen, Schaltjahre, Sommerzeit. PHP nimmt dir das mit der DateTime-Klasse ab.</p>
<h2>Schnelle Ausgabe mit date()</h2>
<pre><span class="k">echo</span> <span class="k">date</span>(<span class="s">"d.m.Y"</span>); <span class="c">// 29.05.2026</span>
<span class="k">echo</span> <span class="k">date</span>(<span class="s">"H:i"</span>); <span class="c">// 14:30</span></pre>
<h2>DateTime – der robuste Weg</h2>
<pre><span class="v">$jetzt</span> = <span class="k">new</span> <span class="t">DateTime</span>();
<span class="v">$termin</span> = <span class="k">new</span> <span class="t">DateTime</span>(<span class="s">"2026-12-24 18:00"</span>);
<span class="k">echo</span> <span class="v">$termin</span>-><span class="f">format</span>(<span class="s">"d.m.Y"</span>); <span class="c">// 24.12.2026</span></pre>
<h2>Rechnen mit Intervallen</h2>
<pre><span class="v">$heute</span> = <span class="k">new</span> <span class="t">DateTime</span>();
<span class="v">$heute</span>-><span class="f">modify</span>(<span class="s">"+2 weeks"</span>);
<span class="v">$diff</span> = <span class="v">$heute</span>-><span class="f">diff</span>(<span class="k">new</span> <span class="t">DateTime</span>(<span class="s">"2026-12-31"</span>));
<span class="k">echo</span> <span class="v">$diff</span>-><span class="v">days</span> . <span class="s">" Tage"</span>;</pre>
<h2>Zeitzonen</h2>
<pre><span class="v">$tz</span> = <span class="k">new</span> <span class="t">DateTimeZone</span>(<span class="s">"Europe/Berlin"</span>);
<span class="v">$d</span> = <span class="k">new</span> <span class="t">DateTime</span>(<span class="s">"now"</span>, <span class="v">$tz</span>);</pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Immer DateTimeImmutable</b>Es gibt <code class="inline">DateTime</code> und <code class="inline">DateTimeImmutable</code>. Bei <code class="inline">DateTime</code> verändert <code class="inline">modify()</code> das Objekt selbst – das führt zu Überraschungen. Nutze besser <code class="inline">DateTimeImmutable</code>: Operationen geben ein neues Objekt zurück und lassen das Original unangetastet.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 12</span>
<h1>Dateien lesen & schreiben</h1>
</div>
<p class="lead">Daten dauerhaft speichern heißt oft: in eine Datei schreiben. PHP bietet dafür angenehm kurze Funktionen.</p>
<h2>Komplette Datei – die einfachen Funktionen</h2>
<pre><span class="c">// ganze Datei lesen</span>
<span class="v">$inhalt</span> = <span class="k">file_get_contents</span>(<span class="s">"notizen.txt"</span>);
<span class="c">// ganze Datei schreiben (überschreibt)</span>
<span class="k">file_put_contents</span>(<span class="s">"notizen.txt"</span>, <span class="s">"Hallo\n"</span>);
<span class="c">// anhängen statt überschreiben</span>
<span class="k">file_put_contents</span>(<span class="s">"log.txt"</span>, <span class="s">"Eintrag\n"</span>, <span class="t">FILE_APPEND</span>);</pre>
<h2>Zeile für Zeile</h2>
<p>Bei großen Dateien liest du nicht alles auf einmal in den Speicher, sondern Zeile für Zeile:</p>
<pre><span class="v">$f</span> = <span class="k">fopen</span>(<span class="s">"gross.csv"</span>, <span class="s">"r"</span>);
<span class="k">while</span> ((<span class="v">$zeile</span> = <span class="k">fgets</span>(<span class="v">$f</span>)) !== <span class="k">false</span>) {
<span class="k">echo</span> <span class="k">trim</span>(<span class="v">$zeile</span>);
}
<span class="k">fclose</span>(<span class="v">$f</span>);</pre>
<h2>Prüfen, ob etwas existiert</h2>
<pre><span class="k">if</span> (<span class="k">file_exists</span>(<span class="s">"config.php"</span>)) { <span class="c">/* ... */</span> }
<span class="k">if</span> (<span class="k">is_dir</span>(<span class="s">"uploads"</span>)) { <span class="c">/* ... */</span> }</pre>
<h2>Verzeichnisse</h2>
<pre><span class="v">$dateien</span> = <span class="k">glob</span>(<span class="s">"bilder/*.jpg"</span>);
<span class="k">foreach</span> (<span class="v">$dateien</span> <span class="k">as</span> <span class="v">$pfad</span>) {
<span class="k">echo</span> <span class="k">basename</span>(<span class="v">$pfad</span>) . <span class="s">"\n"</span>;
}</pre>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>Pfade & Rechte</b>Schreibzugriff scheitert oft an Dateirechten oder falschen Pfaden. Nutze absolute Pfade über <code class="inline">__DIR__</code> (das Verzeichnis der aktuellen Datei), z. B. <code class="inline">__DIR__ . "/data/log.txt"</code>, statt dich auf das Arbeitsverzeichnis zu verlassen.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 13</span>
<h1>JSON & Datenformate</h1>
</div>
<p class="lead">JSON ist das Standardformat für den Datenaustausch im Web. PHP wandelt Arrays und Objekte mit zwei Funktionen hin und her.</p>
<h2>PHP → JSON</h2>
<pre><span class="v">$daten</span> = [
<span class="s">"name"</span> => <span class="s">"Marek"</span>,
<span class="s">"tags"</span> => [<span class="s">"php"</span>, <span class="s">"godot"</span>],
];
<span class="v">$json</span> = <span class="k">json_encode</span>(<span class="v">$daten</span>, <span class="t">JSON_PRETTY_PRINT</span>);
<span class="k">echo</span> <span class="v">$json</span>;</pre>
<pre><span class="s">{
"name": "Marek",
"tags": ["php", "godot"]
}</span></pre>
<h2>JSON → PHP</h2>
<p>Mit <code class="inline">true</code> als zweitem Argument bekommst du ein assoziatives Array statt eines Objekts:</p>
<pre><span class="v">$arr</span> = <span class="k">json_decode</span>(<span class="v">$json</span>, <span class="k">true</span>);
<span class="k">echo</span> <span class="v">$arr</span>[<span class="s">"name"</span>]; <span class="c">// Marek</span></pre>
<h2>Fehler erkennen</h2>
<p>Ist das JSON kaputt, liefert <code class="inline">json_decode</code> <code class="inline">null</code>. Sauberer: per Flag eine Exception werfen lassen:</p>
<pre><span class="k">try</span> {
<span class="v">$arr</span> = <span class="k">json_decode</span>(<span class="v">$json</span>, <span class="k">true</span>, flags: <span class="t">JSON_THROW_ON_ERROR</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>;
}</pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Weitere Formate</b>Für CSV gibt es <code class="inline">fgetcsv()</code> und <code class="inline">fputcsv()</code>. XML liest man am robustesten mit <code class="inline">SimpleXML</code> oder der <code class="inline">DOM</code>-Erweiterung. JSON ist aber im modernen Web der Normalfall.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 14</span>
<h1>Composer & Autoloading</h1>
</div>
<p class="lead">Composer ist PHPs Paketmanager – das Tor zur riesigen Bibliothekswelt. Er installiert fremden Code und lädt deine eigenen Klassen automatisch.</p>
<h2>Ein Projekt starten</h2>
<pre>composer init
<span class="c"># beantwortet ein paar Fragen, erzeugt composer.json</span></pre>
<h2>Pakete installieren</h2>
<pre>composer require guzzlehttp/guzzle
<span class="c"># lädt das Paket + Abhängigkeiten nach vendor/</span></pre>
<p>Composer legt zwei Dateien an: <code class="inline">composer.json</code> (was du willst) und <code class="inline">composer.lock</code> (welche Versionen exakt installiert sind). Beide gehören ins Git-Repository, der Ordner <code class="inline">vendor/</code> nicht.</p>
<h2>Autoloading – nie wieder require</h2>
<p>Das Herzstück: Du bindest <b>eine</b> Datei ein, und alle Klassen laden sich bei Bedarf selbst:</p>
<pre><span class="k">require</span> <span class="s">"vendor/autoload.php"</span>;
<span class="v">$client</span> = <span class="k">new</span> <span class="t">GuzzleHttp\Client</span>();</pre>
<h2>Eigene Klassen automatisch laden (PSR-4)</h2>
<p>In <code class="inline">composer.json</code> verknüpfst du einen Namespace mit einem Ordner:</p>
<pre><span class="s">{
"autoload": {
"psr-4": { "App\\": "src/" }
}
}</span></pre>
<p>Danach einmal <code class="inline">composer dump-autoload</code> – und die Klasse <code class="inline">App\Service\Mailer</code> wird automatisch in <code class="inline">src/Service/Mailer.php</code> gesucht.</p>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Die zwei Befehle, die du brauchst</b>Im Alltag reichen oft <code class="inline">composer require paket</code> zum Hinzufügen und <code class="inline">composer install</code> zum Einrichten eines geklonten Projekts. Mit <code class="inline">--dev</code> markierst du Werkzeuge (Tests, Linter), die nur in der Entwicklung gebraucht werden.</div>
</div>
</section>
<section class="part-divider">
<div class="part-kicker">Teil 3</div>
<h1>Typsystem & moderne Features</h1>
<div class="part-desc">Das, was modernes PHP von altem unterscheidet: ein ausdrucksstarkes Typsystem, Enums, Match, der Pipe-Operator und benannte Argumente.</div>
<div class="part-chapters"><span>15 · Typen & strict_types</span><span>16 · Union-, Nullable- & spezielle Typen</span><span>17 · Enums</span><span>18 · Moderne Syntax-Schmankerl</span></div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 15</span>
<h1>Typen & strict_types</h1>
</div>
<p class="lead">PHP ist dynamisch typisiert, aber du kannst – und solltest – Typen explizit angeben. Das macht Code sicherer und für Editoren verständlich.</p>
<h2>Skalare Typen</h2>
<p>Die Grundtypen für Parameter, Rückgaben und Eigenschaften:</p>
<table>
<tr><th>Typ</th><th>Beispielwert</th></tr>
<tr><td><code>int</code></td><td><code>42</code></td></tr>
<tr><td><code>float</code></td><td><code>3.14</code></td></tr>
<tr><td><code>string</code></td><td><code>"text"</code></td></tr>
<tr><td><code>bool</code></td><td><code>true</code></td></tr>
<tr><td><code>array</code></td><td><code>[1, 2]</code></td></tr>
</table>
<pre><span class="k">function</span> <span class="f">rabatt</span>(<span class="t">float</span> <span class="v">$preis</span>, <span class="t">int</span> <span class="v">$prozent</span>): <span class="t">float</span> {
<span class="k">return</span> <span class="v">$preis</span> * (<span class="s">1</span> - <span class="v">$prozent</span> / <span class="s">100</span>);
}</pre>
<h2>strict_types</h2>
<p>Standardmäßig wandelt PHP Typen weich um: Ein String <code class="inline">"5"</code> wird für einen <code class="inline">int</code>-Parameter zu <code class="inline">5</code>. Mit dieser Zeile ganz oben in der Datei schaltest du das ab:</p>
<pre><span class="t"><?php</span>
<span class="k">declare</span>(strict_types=<span class="s">1</span>);</pre>
<p>Jetzt muss der Typ exakt passen, sonst gibt es einen <code class="inline">TypeError</code>. Das deckt Fehler früh auf.</p>
<h2>Typen für Eigenschaften</h2>
<pre><span class="k">class</span> <span class="t">Konto</span> {
<span class="k">public</span> <span class="t">float</span> <span class="v">$saldo</span> = <span class="s">0.0</span>;
<span class="k">public</span> <span class="t">string</span> <span class="v">$inhaber</span>;
}</pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>strict_types in jede Datei</b>Mach <code class="inline">declare(strict_types=1);</code> zur Gewohnheit – als erste Zeile jeder PHP-Datei. Die wenigen Stellen, an denen es dich zwingt, einen Wert bewusst zu casten, sind genau die Stellen, an denen sonst stille Bugs entstehen.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 16</span>
<h1>Union-, Nullable- & spezielle Typen</h1>
</div>
<p class="lead">Das Typsystem kann mehr als einzelne Grundtypen: Es drückt aus „dieses oder jenes", „dieses oder nichts" und besondere Fälle wie „gibt nie zurück".</p>
<h2>Nullable: Wert oder null</h2>
<p>Ein <code class="inline">?</code> vor dem Typ erlaubt zusätzlich <code class="inline">null</code> – typisch für „nicht gefunden":</p>
<pre><span class="k">function</span> <span class="f">finde</span>(<span class="t">int</span> <span class="v">$id</span>): <span class="t">?User</span> {
<span class="c">// gibt User oder null zurück</span>
}</pre>
<h2>Union: mehrere erlaubte Typen</h2>
<pre><span class="k">function</span> <span class="f">id</span>(<span class="t">int</span>|<span class="t">string</span> <span class="v">$wert</span>): <span class="t">string</span> {
<span class="k">return</span> (<span class="t">string</span>) <span class="v">$wert</span>;
}</pre>
<h2>Spezielle Rückgabetypen</h2>
<table>
<tr><th>Typ</th><th>Bedeutung</th></tr>
<tr><td><code>void</code></td><td>gibt nichts zurück</td></tr>
<tr><td><code>never</code></td><td>kehrt nie zurück (wirft / beendet)</td></tr>
<tr><td><code>mixed</code></td><td>jeder beliebige Typ</td></tr>
<tr><td><code>self</code> / <code>static</code></td><td>die eigene Klasse</td></tr>
</table>
<pre><span class="k">function</span> <span class="f">abbruch</span>(<span class="t">string</span> <span class="v">$msg</span>): <span class="t">never</span> {
<span class="k">throw new</span> <span class="t">RuntimeException</span>(<span class="v">$msg</span>);
}</pre>
<h2>Intersection-Typen</h2>
<p>Seit PHP 8.1: ein Wert, der <b>mehrere</b> Interfaces zugleich erfüllt:</p>
<pre><span class="k">function</span> <span class="f">verarbeite</span>(<span class="t">Countable</span>&<span class="t">Iterator</span> <span class="v">$x</span>): <span class="t">void</span> { <span class="c">/* ... */</span> }</pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>mixed sparsam einsetzen</b><code class="inline">mixed</code> bedeutet „alles erlaubt” und schaltet damit den Schutz des Typsystems faktisch ab. Es ist gelegentlich nötig (z. B. bei generischen Containern), sollte aber die Ausnahme bleiben – je präziser dein Typ, desto mehr Fehler fängt PHP für dich ab.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 17</span>
<h1>Enums</h1>
</div>
<p class="lead">Ein Enum ist ein eigener Typ mit einer festen, abgeschlossenen Menge möglicher Werte. Statt loser Strings wie <code class="inline">"aktiv"</code> bekommst du echte, typsichere Optionen.</p>
<h2>Das Problem ohne Enums</h2>
<p>Früher übergab man Status als String – fehleranfällig, weil Tippfehler erst zur Laufzeit auffallen:</p>
<pre><span class="v">$status</span> = <span class="s">"aktif"</span>; <span class="c">// Tippfehler – PHP merkt nichts</span></pre>
<h2>Reines Enum</h2>
<pre><span class="k">enum</span> <span class="t">Status</span> {
<span class="k">case</span> <span class="v">Aktiv</span>;
<span class="k">case</span> <span class="v">Pausiert</span>;
<span class="k">case</span> <span class="v">Gesperrt</span>;
}
<span class="k">function</span> <span class="f">setze</span>(<span class="t">Status</span> <span class="v">$s</span>): <span class="t">void</span> { <span class="c">/* ... */</span> }
<span class="f">setze</span>(<span class="t">Status</span>::<span class="v">Aktiv</span>); <span class="c">// nur gültige Werte möglich</span></pre>
<h2>Backed Enum – mit Wert hinterlegt</h2>
<p>Wenn der Wert in einer Datenbank oder API auftaucht, hinterlegst du ihn:</p>
<pre><span class="k">enum</span> <span class="t">Rolle</span>: <span class="t">string</span> {
<span class="k">case</span> <span class="v">Admin</span> = <span class="s">"admin"</span>;
<span class="k">case</span> <span class="v">Editor</span> = <span class="s">"editor"</span>;
<span class="k">case</span> <span class="v">Gast</span> = <span class="s">"guest"</span>;
}
<span class="v">$r</span> = <span class="t">Rolle</span>::<span class="f">from</span>(<span class="s">"admin"</span>); <span class="c">// aus DB-Wert</span>
<span class="k">echo</span> <span class="v">$r</span>-><span class="v">value</span>; <span class="c">// "admin"</span>
<span class="k">echo</span> <span class="v">$r</span>-><span class="v">name</span>; <span class="c">// "Admin"</span></pre>
<h2>Methoden im Enum</h2>
<p>Enums dürfen Methoden haben – ideal für ableitbare Eigenschaften:</p>
<pre><span class="k">enum</span> <span class="t">Ampel</span>: <span class="t">string</span> {
<span class="k">case</span> <span class="v">Rot</span> = <span class="s">"rot"</span>;
<span class="k">case</span> <span class="v">Gruen</span> = <span class="s">"gruen"</span>;
<span class="k">public function</span> <span class="f">darfFahren</span>(): <span class="t">bool</span> {
<span class="k">return</span> <span class="v">$this</span> === <span class="t">Ampel</span>::<span class="v">Gruen</span>;
}
}</pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Enum + match = unschlagbar</b>Enums spielen perfekt mit <code class="inline">match</code> zusammen: Da die Werte abgeschlossen sind, kann dein Editor warnen, wenn du einen Fall vergisst. Ersetze lose String-Konstanten in deinem Code nach und nach durch Enums.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 18</span>
<h1>Moderne Syntax-Schmankerl</h1>
</div>
<p class="lead">PHP 8 hat die Sprache spürbar moderner gemacht. Diese Features schreiben kürzeren, klareren Code – und sind heute Best Practice.</p>
<h2>Benannte Argumente</h2>
<p>Argumente per Namen übergeben – die Reihenfolge wird egal, optionale Werte überspringbar:</p>
<pre><span class="f">erstelle</span>(name: <span class="s">"Box"</span>, hoehe: <span class="s">10</span>, farbe: <span class="s">"blau"</span>);</pre>
<h2>Der Nullsafe-Operator</h2>
<p><code class="inline">?-></code> bricht eine Kette ab, sobald ein Glied <code class="inline">null</code> ist – statt einen Fehler zu werfen:</p>
<pre><span class="v">$land</span> = <span class="v">$user</span>?-><span class="f">adresse</span>()?-><span class="v">land</span>;
<span class="c">// null, falls user oder adresse() null ist</span></pre>
<h2>Der Pipe-Operator (PHP 8.5)</h2>
<p>Ganz neu: <code class="inline">|></code> reicht einen Wert durch eine Kette von Funktionen – von links nach rechts lesbar statt verschachtelt:</p>
<pre><span class="c">// vorher: tief verschachtelt</span>
<span class="v">$r</span> = <span class="k">array_sum</span>(<span class="k">array_map</span>(<span class="k">fn</span>(<span class="v">$x</span>) => <span class="v">$x</span> * <span class="s">2</span>, <span class="v">$zahlen</span>));
<span class="c">// mit Pipe: von links nach rechts</span>
<span class="v">$r</span> = <span class="v">$zahlen</span>
|> <span class="k">fn</span>(<span class="v">$a</span>) => <span class="k">array_map</span>(<span class="k">fn</span>(<span class="v">$x</span>) => <span class="v">$x</span> * <span class="s">2</span>, <span class="v">$a</span>)
|> <span class="k">array_sum</span>(...);</pre>
<h2>First-class Callable Syntax</h2>
<p>Eine Funktion als Wert weiterreichen, ohne sie aufzurufen – das <code class="inline">(...)</code> macht's:</p>
<pre><span class="v">$fn</span> = <span class="k">strtoupper</span>(...);
<span class="k">echo</span> <span class="v">$fn</span>(<span class="s">"hallo"</span>); <span class="c">// HALLO</span>
<span class="v">$gross</span> = <span class="k">array_map</span>(<span class="k">strtoupper</span>(...), <span class="v">$woerter</span>);</pre>
<h2>Destructuring</h2>
<p>Array-Werte in einem Schritt auf Variablen verteilen:</p>
<pre>[<span class="v">$jahr</span>, <span class="v">$monat</span>, <span class="v">$tag</span>] = [<span class="s">2026</span>, <span class="s">5</span>, <span class="s">29</span>];
[<span class="s">"name"</span> => <span class="v">$name</span>] = <span class="v">$person</span>;</pre>
<div class="callout deep">
<div class="callout-icon">◆</div>
<div class="callout-body"><b>Pipe-Operator: brandneu</b>Der <code class="inline">|></code>-Operator kam erst mit PHP 8.5 (Ende 2025). Er ist großartig für Datentransformationen, aber prüfe vor dem Einsatz, dass deine Zielumgebung wirklich auf 8.5 läuft – auf älteren Versionen ist es schlicht ein Syntaxfehler.</div>
</div>
</section>
<section class="part-divider">
<div class="part-kicker">Teil 4</div>
<h1>Objektorientierung</h1>
<div class="part-desc">Klassen und Objekte sind das Rückgrat größerer PHP-Programme. Von der ersten Klasse über Vererbung und Interfaces bis zu Traits und der Magie hinter den Kulissen.</div>
<div class="part-chapters"><span>19 · Klassen & Objekte</span><span>20 · Sichtbarkeit & Kapselung</span><span>21 · Konstruktoren modern</span><span>22 · Vererbung</span><span>23 · Abstrakte Klassen & Interfaces</span><span>24 · Traits</span><span>25 · Statisches & Konstanten</span><span>26 · Magische Methoden</span></div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 19</span>
<h1>Klassen & Objekte</h1>
</div>
<p class="lead">Eine Klasse ist ein Bauplan, ein Objekt das fertige Ding. Die Klasse beschreibt, welche Daten (Eigenschaften) und welche Fähigkeiten (Methoden) etwas hat.</p>
<h2>Erste Klasse</h2>
<pre><span class="k">class</span> <span class="t">Hund</span> {
<span class="k">public</span> <span class="t">string</span> <span class="v">$name</span>;
<span class="k">public function</span> <span class="f">bellen</span>(): <span class="t">string</span> {
<span class="k">return</span> <span class="v">$this</span>-><span class="v">name</span> . <span class="s">" sagt Wuff!"</span>;
}
}</pre>
<h2>Objekte erzeugen</h2>
<p>Mit <code class="inline">new</code> erstellst du eine konkrete Instanz. Auf Eigenschaften und Methoden greifst du mit <code class="inline">-></code> zu:</p>
<pre><span class="v">$bello</span> = <span class="k">new</span> <span class="t">Hund</span>();
<span class="v">$bello</span>-><span class="v">name</span> = <span class="s">"Bello"</span>;
<span class="k">echo</span> <span class="v">$bello</span>-><span class="f">bellen</span>(); <span class="c">// Bello sagt Wuff!</span></pre>
<h2>$this – das Objekt selbst</h2>
<p>Innerhalb einer Methode verweist <code class="inline">$this</code> auf das aktuelle Objekt. So greift eine Methode auf die Eigenschaften ihres eigenen Objekts zu.</p>
<h2>Mehrere unabhängige Objekte</h2>
<pre><span class="v">$a</span> = <span class="k">new</span> <span class="t">Hund</span>(); <span class="v">$a</span>-><span class="v">name</span> = <span class="s">"Rex"</span>;
<span class="v">$b</span> = <span class="k">new</span> <span class="t">Hund</span>(); <span class="v">$b</span>-><span class="v">name</span> = <span class="s">"Luna"</span>;
<span class="c">// $a und $b sind komplett getrennt</span></pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Klasse vs. Objekt</b>Die <b>Klasse</b> <code class="inline">Hund</code> ist der Bauplan – sie existiert einmal. Jedes mit <code class="inline">new</code> erzeugte <b>Objekt</b> ist eine eigenständige Instanz mit eigenen Daten. Aus einem Bauplan baust du beliebig viele Häuser.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 20</span>
<h1>Sichtbarkeit & Kapselung</h1>
</div>
<p class="lead">Nicht jeder Teil eines Objekts soll von außen erreichbar sein. Sichtbarkeits-Modifikatoren schützen die innere Logik – das nennt man Kapselung.</p>
<h2>Die drei Stufen</h2>
<table>
<tr><th>Modifikator</th><th>Zugriff von …</th></tr>
<tr><td><code>public</code></td><td>überall</td></tr>
<tr><td><code>protected</code></td><td>Klasse + Unterklassen</td></tr>
<tr><td><code>private</code></td><td>nur dieser Klasse selbst</td></tr>
</table>
<h2>Warum kapseln?</h2>
<p>Eine private Eigenschaft kann nicht von außen in einen ungültigen Zustand gebracht werden. Du steuerst den Zugriff über Methoden:</p>
<pre><span class="k">class</span> <span class="t">Konto</span> {
<span class="k">private</span> <span class="t">float</span> <span class="v">$saldo</span> = <span class="s">0</span>;
<span class="k">public function</span> <span class="f">einzahlen</span>(<span class="t">float</span> <span class="v">$betrag</span>): <span class="t">void</span> {
<span class="k">if</span> (<span class="v">$betrag</span> <= <span class="s">0</span>) {
<span class="k">throw new</span> <span class="t">InvalidArgumentException</span>(<span class="s">"> 0 nötig"</span>);
}
<span class="v">$this</span>-><span class="v">saldo</span> += <span class="v">$betrag</span>;
}
<span class="k">public function</span> <span class="f">saldo</span>(): <span class="t">float</span> {
<span class="k">return</span> <span class="v">$this</span>-><span class="v">saldo</span>;
}
}</pre>
<p>Von außen kann niemand <code class="inline">$konto->saldo = -999</code> setzen – der Weg führt nur über <code class="inline">einzahlen()</code>, das prüft.</p>
<h2>Asymmetrische Sichtbarkeit (PHP 8.4)</h2>
<p>Neu: von außen lesbar, aber nur intern schreibbar – in einer Zeile:</p>
<pre><span class="k">class</span> <span class="t">User</span> {
<span class="k">public</span> <span class="k">private(set)</span> <span class="t">string</span> <span class="v">$id</span>;
}
<span class="c">// $user->id lesen: ok / setzen von außen: Fehler</span></pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Standard: so privat wie möglich</b>Eine gute Faustregel: Mach alles <code class="inline">private</code>, bis du einen Grund hast, es zu öffnen. Je kleiner die öffentliche Oberfläche einer Klasse, desto leichter kannst du ihre Interna später ändern, ohne anderen Code zu brechen.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 21</span>
<h1>Konstruktoren modern</h1>
</div>
<p class="lead">Der Konstruktor läuft automatisch beim Erzeugen eines Objekts. PHP 8 hat ihn drastisch verkürzt – das spart viel Tipparbeit.</p>
<h2>Klassischer Konstruktor</h2>
<pre><span class="k">class</span> <span class="t">Punkt</span> {
<span class="k">public</span> <span class="t">float</span> <span class="v">$x</span>;
<span class="k">public</span> <span class="t">float</span> <span class="v">$y</span>;
<span class="k">public function</span> <span class="f">__construct</span>(<span class="t">float</span> <span class="v">$x</span>, <span class="t">float</span> <span class="v">$y</span>) {
<span class="v">$this</span>-><span class="v">x</span> = <span class="v">$x</span>;
<span class="v">$this</span>-><span class="v">y</span> = <span class="v">$y</span>;
}
}</pre>
<h2>Constructor Property Promotion</h2>
<p>Dasselbe in modern: Sichtbarkeit direkt in die Parameterliste schreiben – Eigenschaft und Zuweisung entstehen automatisch:</p>
<pre><span class="k">class</span> <span class="t">Punkt</span> {
<span class="k">public function</span> <span class="f">__construct</span>(
<span class="k">public</span> <span class="t">float</span> <span class="v">$x</span>,
<span class="k">public</span> <span class="t">float</span> <span class="v">$y</span>,
) {}
}
<span class="v">$p</span> = <span class="k">new</span> <span class="t">Punkt</span>(<span class="s">3</span>, <span class="s">4</span>);
<span class="k">echo</span> <span class="v">$p</span>-><span class="v">x</span>; <span class="c">// 3</span></pre>
<p>Beide Versionen sind exakt gleichwertig – die zweite ist nur viel kürzer.</p>
<h2>readonly für Unveränderliches</h2>
<p>Eine <code class="inline">readonly</code>-Eigenschaft darf nach dem Setzen im Konstruktor nicht mehr geändert werden – perfekt für Wertobjekte:</p>
<pre><span class="k">class</span> <span class="t">Geld</span> {
<span class="k">public function</span> <span class="f">__construct</span>(
<span class="k">public</span> <span class="k">readonly</span> <span class="t">int</span> <span class="v">$cent</span>,
<span class="k">public</span> <span class="k">readonly</span> <span class="t">string</span> <span class="v">$waehrung</span>,
) {}
}
<span class="v">$preis</span> = <span class="k">new</span> <span class="t">Geld</span>(<span class="s">999</span>, <span class="s">"EUR"</span>);
<span class="c">// $preis->cent = 0; -> Error</span></pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>readonly classes (PHP 8.2)</b>Statt jede Eigenschaft einzeln als <code class="inline">readonly</code> zu markieren, kannst du seit 8.2 die ganze Klasse so deklarieren: <code class="inline">readonly class Geld { ... }</code>. Ideal für DTOs und Wertobjekte, die nach Erzeugung unveränderlich bleiben sollen.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 22</span>
<h1>Vererbung</h1>
</div>
<p class="lead">Vererbung lässt eine Klasse die Eigenschaften und Methoden einer anderen übernehmen – und erweitern. So vermeidest du Wiederholung bei verwandten Typen.</p>
<h2>extends</h2>
<pre><span class="k">class</span> <span class="t">Tier</span> {
<span class="k">public function</span> <span class="f">__construct</span>(<span class="k">public</span> <span class="t">string</span> <span class="v">$name</span>) {}
<span class="k">public function</span> <span class="f">geraeusch</span>(): <span class="t">string</span> { <span class="k">return</span> <span class="s">"..."</span>; }
}
<span class="k">class</span> <span class="t">Katze</span> <span class="k">extends</span> <span class="t">Tier</span> {
<span class="k">public function</span> <span class="f">geraeusch</span>(): <span class="t">string</span> { <span class="k">return</span> <span class="s">"Miau"</span>; }
}
<span class="v">$mieze</span> = <span class="k">new</span> <span class="t">Katze</span>(<span class="s">"Minka"</span>);
<span class="k">echo</span> <span class="v">$mieze</span>-><span class="v">name</span>; <span class="c">// von Tier geerbt</span>
<span class="k">echo</span> <span class="v">$mieze</span>-><span class="f">geraeusch</span>(); <span class="c">// Miau (überschrieben)</span></pre>
<h2>parent:: – die Elternversion aufrufen</h2>
<p>Beim Überschreiben kannst du die ursprüngliche Methode trotzdem mitnutzen:</p>
<pre><span class="k">class</span> <span class="t">Hund</span> <span class="k">extends</span> <span class="t">Tier</span> {
<span class="k">public function</span> <span class="f">__construct</span>(<span class="t">string</span> <span class="v">$name</span>, <span class="k">public</span> <span class="t">string</span> <span class="v">$rasse</span>) {
<span class="k">parent</span>::<span class="f">__construct</span>(<span class="v">$name</span>);
}
}</pre>
<h2>final – Vererbung stoppen</h2>
<p><code class="inline">final</code> verhindert, dass eine Klasse erweitert oder eine Methode überschrieben wird:</p>
<pre><span class="k">final class</span> <span class="t">Uuid</span> { <span class="c">/* niemand darf erben */</span> }</pre>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>Vererbung mit Bedacht</b>Tiefe Vererbungsbäume werden schnell unübersichtlich. Eine erprobte Regel lautet „Komposition vor Vererbung”: Statt von einer Klasse zu erben, gib deinem Objekt das andere Objekt als Eigenschaft mit. Vererbung passt nur, wenn wirklich eine „ist ein”-Beziehung besteht (eine Katze <i>ist ein</i> Tier).</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 23</span>
<h1>Abstrakte Klassen & Interfaces</h1>
</div>
<p class="lead">Beide definieren Verträge: „Wer das sein will, muss diese Methoden bieten." Interfaces beschreiben reine Fähigkeiten, abstrakte Klassen liefern zusätzlich teilweise Umsetzung.</p>
<h2>Interface – der reine Vertrag</h2>
<p>Ein Interface listet Methoden ohne Rumpf. Jede Klasse, die es <code class="inline">implements</code>, muss sie ausfüllen:</p>
<pre><span class="k">interface</span> <span class="t">Zahlbar</span> {
<span class="k">public function</span> <span class="f">betrag</span>(): <span class="t">int</span>;
}
<span class="k">class</span> <span class="t">Rechnung</span> <span class="k">implements</span> <span class="t">Zahlbar</span> {
<span class="k">public function</span> <span class="f">betrag</span>(): <span class="t">int</span> { <span class="k">return</span> <span class="s">4200</span>; }
}</pre>
<p>Der Gewinn: Du programmierst gegen den Vertrag, nicht gegen eine konkrete Klasse. Eine Funktion kann jedes <code class="inline">Zahlbar</code> entgegennehmen:</p>
<pre><span class="k">function</span> <span class="f">verbuche</span>(<span class="t">Zahlbar</span> <span class="v">$x</span>): <span class="t">void</span> { <span class="c">/* ... */</span> }</pre>
<h2>Mehrere Interfaces</h2>
<pre><span class="k">class</span> <span class="t">Bestellung</span> <span class="k">implements</span> <span class="t">Zahlbar</span>, <span class="t">JsonSerializable</span> { <span class="c">/* ... */</span> }</pre>
<h2>Abstrakte Klasse – Vertrag plus Basis</h2>
<p>Sie kann fertige Methoden mitbringen <b>und</b> abstrakte erzwingen. Selbst instanziieren lässt sie sich nicht:</p>
<pre><span class="k">abstract class</span> <span class="t">Form</span> {
<span class="k">abstract public function</span> <span class="f">flaeche</span>(): <span class="t">float</span>;
<span class="k">public function</span> <span class="f">beschreibung</span>(): <span class="t">string</span> {
<span class="k">return</span> <span class="s">"Fläche: "</span> . <span class="v">$this</span>-><span class="f">flaeche</span>();
}
}
<span class="k">class</span> <span class="t">Kreis</span> <span class="k">extends</span> <span class="t">Form</span> {
<span class="k">public function</span> <span class="f">__construct</span>(<span class="k">private</span> <span class="t">float</span> <span class="v">$r</span>) {}
<span class="k">public function</span> <span class="f">flaeche</span>(): <span class="t">float</span> { <span class="k">return</span> <span class="s">3.14159</span> * <span class="v">$this</span>-><span class="v">r</span> ** <span class="s">2</span>; }
}</pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Wann was?</b>Faustregel: <b>Interface</b>, wenn du nur eine Fähigkeit beschreibst und Klassen ganz unterschiedlicher Herkunft sie erfüllen sollen. <b>Abstrakte Klasse</b>, wenn verwandte Klassen gemeinsamen Code teilen <i>und</i> einen Pflichtteil haben. Eine Klasse kann viele Interfaces, aber nur eine (abstrakte) Elternklasse haben.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 24</span>
<h1>Traits</h1>
</div>
<p class="lead">Ein Trait ist ein Stück wiederverwendbarer Code, das du in mehrere Klassen „hineinkopierst" – ohne Vererbung. Er löst das Problem, dass eine Klasse nur von einer Klasse erben kann.</p>
<h2>Trait definieren und nutzen</h2>
<pre><span class="k">trait</span> <span class="t">Zeitstempel</span> {
<span class="k">public</span> <span class="t">?DateTimeImmutable</span> <span class="v">$erstellt</span> = <span class="k">null</span>;
<span class="k">public function</span> <span class="f">jetztSetzen</span>(): <span class="t">void</span> {
<span class="v">$this</span>-><span class="v">erstellt</span> = <span class="k">new</span> <span class="t">DateTimeImmutable</span>();
}
}
<span class="k">class</span> <span class="t">Artikel</span> {
<span class="k">use</span> <span class="t">Zeitstempel</span>;
}
<span class="k">class</span> <span class="t">Kommentar</span> {
<span class="k">use</span> <span class="t">Zeitstempel</span>; <span class="c">// gleiche Funktionalität, keine Vererbung</span>
}</pre>
<h2>Mehrere Traits kombinieren</h2>
<pre><span class="k">class</span> <span class="t">Post</span> {
<span class="k">use</span> <span class="t">Zeitstempel</span>, <span class="t">Sluggable</span>;
}</pre>
<h2>Namenskonflikte auflösen</h2>
<p>Bringen zwei Traits eine gleichnamige Methode mit, wählst du explizit aus:</p>
<pre><span class="k">class</span> <span class="t">Seite</span> {
<span class="k">use</span> <span class="t">A</span>, <span class="t">B</span> {
<span class="t">A</span>::<span class="f">hallo</span> <span class="k">insteadof</span> <span class="t">B</span>;
<span class="t">B</span>::<span class="f">hallo</span> <span class="k">as</span> <span class="f">halloB</span>;
}
}</pre>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>Traits sparsam einsetzen</b>Traits sind mächtig, verwischen aber die Herkunft von Code – eine Klasse kann plötzlich Methoden aus drei Dateien haben. Nutze sie für klar abgegrenzte, querschnittliche Fähigkeiten (Zeitstempel, Logging). Für echte Typ-Beziehungen sind Interfaces die sauberere Wahl.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 25</span>
<h1>Statisches & Konstanten</h1>
</div>
<p class="lead">Manche Daten und Methoden gehören zur Klasse selbst, nicht zu einzelnen Objekten. Dafür gibt es statische Eigenschaften, Methoden und Klassen-Konstanten.</p>
<h2>Statische Eigenschaften & Methoden</h2>
<p>Zugriff erfolgt über den Klassennamen mit <code class="inline">::</code>, ohne ein Objekt zu erzeugen:</p>
<pre><span class="k">class</span> <span class="t">Zaehler</span> {
<span class="k">public static</span> <span class="t">int</span> <span class="v">$anzahl</span> = <span class="s">0</span>;
<span class="k">public static function</span> <span class="f">hoch</span>(): <span class="t">void</span> {
<span class="k">self</span>::<span class="v">$anzahl</span>++;
}
}
<span class="t">Zaehler</span>::<span class="f">hoch</span>();
<span class="k">echo</span> <span class="t">Zaehler</span>::<span class="v">$anzahl</span>; <span class="c">// 1</span></pre>
<h2>Klassen-Konstanten</h2>
<pre><span class="k">class</span> <span class="t">Http</span> {
<span class="k">const</span> <span class="v">OK</span> = <span class="s">200</span>;
<span class="k">const</span> <span class="v">NOT_FOUND</span> = <span class="s">404</span>;
}
<span class="k">echo</span> <span class="t">Http</span>::<span class="v">NOT_FOUND</span>; <span class="c">// 404</span></pre>
<h2>Typisierte Konstanten (PHP 8.3)</h2>
<pre><span class="k">class</span> <span class="t">Config</span> {
<span class="k">const</span> <span class="t">string</span> <span class="v">ENV</span> = <span class="s">"prod"</span>;
}</pre>
<h2>Das Named Constructor Pattern</h2>
<p>Statische Methoden als sprechende Alternativen zu <code class="inline">new</code>:</p>
<pre><span class="k">class</span> <span class="t">Temperatur</span> {
<span class="k">private function</span> <span class="f">__construct</span>(<span class="k">public</span> <span class="k">readonly</span> <span class="t">float</span> <span class="v">$celsius</span>) {}
<span class="k">public static function</span> <span class="f">ausFahrenheit</span>(<span class="t">float</span> <span class="v">$f</span>): <span class="k">static</span> {
<span class="k">return new</span> <span class="k">self</span>((<span class="v">$f</span> - <span class="s">32</span>) * <span class="s">5</span> / <span class="s">9</span>);
}
}
<span class="v">$t</span> = <span class="t">Temperatur</span>::<span class="f">ausFahrenheit</span>(<span class="s">98.6</span>);</pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>static sparsam</b>Statischer Zustand (veränderliche statische Eigenschaften) ist im Grunde globaler Zustand und erschwert Tests. Statische Methoden als <i>Named Constructors</i> oder reine Hilfsfunktionen sind dagegen völlig in Ordnung.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 26</span>
<h1>Magische Methoden</h1>
</div>
<p class="lead">„Magische" Methoden beginnen mit zwei Unterstrichen und werden von PHP automatisch in bestimmten Situationen aufgerufen – etwa wenn ein Objekt als String genutzt wird.</p>
<h2>__toString</h2>
<p>Definiert, wie ein Objekt zu Text wird:</p>
<pre><span class="k">class</span> <span class="t">Geld</span> {
<span class="k">public function</span> <span class="f">__construct</span>(<span class="k">public</span> <span class="t">int</span> <span class="v">$cent</span>) {}
<span class="k">public function</span> <span class="f">__toString</span>(): <span class="t">string</span> {
<span class="k">return</span> <span class="k">number_format</span>(<span class="v">$this</span>-><span class="v">cent</span> / <span class="s">100</span>, <span class="s">2</span>) . <span class="s">" €"</span>;
}
}
<span class="k">echo</span> <span class="k">new</span> <span class="t">Geld</span>(<span class="s">1999</span>); <span class="c">// 19,99 €</span></pre>
<h2>__get und __set</h2>
<p>Fangen Zugriffe auf nicht existierende Eigenschaften ab – Basis vieler Frameworks:</p>
<pre><span class="k">class</span> <span class="t">Bag</span> {
<span class="k">private</span> <span class="t">array</span> <span class="v">$data</span> = [];
<span class="k">public function</span> <span class="f">__get</span>(<span class="t">string</span> <span class="v">$k</span>) { <span class="k">return</span> <span class="v">$this</span>-><span class="v">data</span>[<span class="v">$k</span>] ?? <span class="k">null</span>; }
<span class="k">public function</span> <span class="f">__set</span>(<span class="t">string</span> <span class="v">$k</span>, <span class="v">$v</span>) { <span class="v">$this</span>-><span class="v">data</span>[<span class="v">$k</span>] = <span class="v">$v</span>; }
}
<span class="v">$b</span> = <span class="k">new</span> <span class="t">Bag</span>();
<span class="v">$b</span>-><span class="v">titel</span> = <span class="s">"Test"</span>; <span class="c">// __set</span>
<span class="k">echo</span> <span class="v">$b</span>-><span class="v">titel</span>; <span class="c">// __get -> Test</span></pre>
<h2>__call und __invoke</h2>
<p><code class="inline">__call</code> fängt Aufrufe nicht existierender Methoden ab; <code class="inline">__invoke</code> macht ein Objekt aufrufbar wie eine Funktion:</p>
<pre><span class="k">class</span> <span class="t">Verdoppler</span> {
<span class="k">public function</span> <span class="f">__invoke</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="s">2</span>; }
}
<span class="v">$f</span> = <span class="k">new</span> <span class="t">Verdoppler</span>();
<span class="k">echo</span> <span class="v">$f</span>(<span class="s">21</span>); <span class="c">// 42</span></pre>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>Magie versteckt Logik</b>Magische Methoden sind elegant, aber sie machen Code schwerer nachvollziehbar – Editoren erkennen die so erzeugten Eigenschaften und Methoden oft nicht. Setze sie gezielt ein (etwa <code class="inline">__toString</code> für Wertobjekte) und bevorzuge sonst explizite, deklarierte Methoden.</div>
</div>
</section>
<section class="part-divider">
<div class="part-kicker">Teil 5</div>
<h1>Fortgeschrittene Sprache</h1>
<div class="part-desc">Tieferes Sprach-Handwerk: Collections, Generatoren, Closures mit Bindung, Attribute und Reflection – die Werkzeuge hinter Frameworks.</div>
<div class="part-chapters"><span>27 · Collections & Generics-Denken</span><span>28 · Iteratoren & Generatoren</span><span>29 · Closures & Bindung</span><span>30 · Attribute</span><span>31 · Reflection</span><span>32 · Namespaces im Detail</span></div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 27</span>
<h1>Collections & Generics-Denken</h1>
</div>
<p class="lead">PHP hat keine echten Generics in der Sprache – aber das Denken in typisierten Sammlungen lohnt sich. Mit ein wenig Disziplin und Werkzeugen bekommst du fast denselben Komfort.</p>
<h2>Das Problem mit nackten Arrays</h2>
<p>Ein <code class="inline">array</code> sagt nichts darüber, was drinsteckt. Eine Funktion, die <code class="inline">User[]</code> erwartet, kann das im Typsystem nicht ausdrücken:</p>
<pre><span class="k">function</span> <span class="f">namen</span>(<span class="t">array</span> <span class="v">$users</span>): <span class="t">array</span> {
<span class="c">// array von WAS? Editor weiß es nicht</span>
}</pre>
<h2>Lösung 1: PHPDoc-Generics</h2>
<p>Statische Analyse-Werkzeuge (Teil 7) verstehen Generics in Kommentaren – die Sprache ignoriert sie, der Editor nicht:</p>
<pre><span class="c">/** @param User[] $users @return string[] */</span>
<span class="k">function</span> <span class="f">namen</span>(<span class="t">array</span> <span class="v">$users</span>): <span class="t">array</span> { <span class="c">/* ... */</span> }</pre>
<h2>Lösung 2: Eine eigene Collection-Klasse</h2>
<p>Du kapselst das Array in einer Klasse, die nur den gewünschten Typ akzeptiert:</p>
<pre><span class="k">final class</span> <span class="t">UserListe</span> <span class="k">implements</span> <span class="t">IteratorAggregate</span> {
<span class="k">private</span> <span class="t">array</span> <span class="v">$items</span> = [];
<span class="k">public function</span> <span class="f">add</span>(<span class="t">User</span> <span class="v">$u</span>): <span class="t">void</span> {
<span class="v">$this</span>-><span class="v">items</span>[] = <span class="v">$u</span>; <span class="c">// nur User möglich</span>
}
<span class="k">public function</span> <span class="f">getIterator</span>(): <span class="t">Iterator</span> {
<span class="k">return new</span> <span class="t">ArrayIterator</span>(<span class="v">$this</span>-><span class="v">items</span>);
}
}</pre>
<p>Jetzt ist <code class="inline">foreach</code> über die Liste möglich, und niemand kann versehentlich einen String hineinlegen.</p>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Warum keine echten Generics?</b>Echte Generics würden tief in die PHP-Laufzeit eingreifen und kosteten Performance. Die Community löst das pragmatisch über PHPDoc plus statische Analyse – in der Praxis bekommst du damit fast die volle Typsicherheit, ohne Laufzeit-Kosten.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 28</span>
<h1>Iteratoren & Generatoren</h1>
</div>
<p class="lead">Manchmal willst du über etwas iterieren, ohne alle Werte gleichzeitig im Speicher zu halten – etwa Millionen Zeilen aus einer Datei. Generatoren machen das mit minimalem Code.</p>
<h2>Der yield-Befehl</h2>
<p>Eine Funktion mit <code class="inline">yield</code> ist ein <b>Generator</b>: Sie liefert Werte einen nach dem anderen, pausiert dazwischen und merkt sich ihren Zustand:</p>
<pre><span class="k">function</span> <span class="f">zaehleBis</span>(<span class="t">int</span> <span class="v">$max</span>): <span class="t">Generator</span> {
<span class="k">for</span> (<span class="v">$i</span> = <span class="s">1</span>; <span class="v">$i</span> <= <span class="v">$max</span>; <span class="v">$i</span>++) {
<span class="k">yield</span> <span class="v">$i</span>;
}
}
<span class="k">foreach</span> (<span class="f">zaehleBis</span>(<span class="s">3</span>) <span class="k">as</span> <span class="v">$n</span>) {
<span class="k">echo</span> <span class="v">$n</span>; <span class="c">// 123</span>
}</pre>
<h2>Der Speicher-Vorteil</h2>
<p>Eine riesige Datei zeilenweise verarbeiten, ohne sie komplett zu laden:</p>
<pre><span class="k">function</span> <span class="f">zeilen</span>(<span class="t">string</span> <span class="v">$pfad</span>): <span class="t">Generator</span> {
<span class="v">$f</span> = <span class="k">fopen</span>(<span class="v">$pfad</span>, <span class="s">"r"</span>);
<span class="k">while</span> ((<span class="v">$z</span> = <span class="k">fgets</span>(<span class="v">$f</span>)) !== <span class="k">false</span>) {
<span class="k">yield</span> <span class="k">trim</span>(<span class="v">$z</span>);
}
<span class="k">fclose</span>(<span class="v">$f</span>);
}
<span class="c">// verbraucht konstant wenig Speicher – egal wie groß die Datei</span></pre>
<h2>Schlüssel mitliefern</h2>
<pre><span class="k">yield</span> <span class="v">$key</span> => <span class="v">$value</span>;</pre>
<h2>Das Iterator-Interface von Hand</h2>
<p>Generatoren decken 95 % der Fälle ab. Für komplexe Iteration implementierst du <code class="inline">Iterator</code> direkt – mit <code class="inline">current()</code>, <code class="inline">next()</code>, <code class="inline">valid()</code>, <code class="inline">key()</code>, <code class="inline">rewind()</code>.</p>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Generatoren für große Datenmengen</b>Immer wenn du ein großes Array baust, nur um einmal darüber zu iterieren, ist ein Generator die bessere Wahl: gleicher <code class="inline">foreach</code>-Komfort, aber konstanter Speicherverbrauch statt linear wachsendem.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 29</span>
<h1>Closures & Bindung</h1>
</div>
<p class="lead">Eine Closure ist eine anonyme Funktion, die sich Werte aus ihrer Umgebung „merkt". Sie ist die Grundlage von Callbacks, Event-Handlern und vielem Framework-Code.</p>
<h2>use – Werte einfangen</h2>
<p>Mit <code class="inline">use</code> nimmt eine anonyme Funktion Variablen von außen mit hinein:</p>
<pre><span class="v">$faktor</span> = <span class="s">3</span>;
<span class="v">$mal</span> = <span class="k">function</span>(<span class="v">$x</span>) <span class="k">use</span> (<span class="v">$faktor</span>) {
<span class="k">return</span> <span class="v">$x</span> * <span class="v">$faktor</span>;
};
<span class="k">echo</span> <span class="v">$mal</span>(<span class="s">5</span>); <span class="c">// 15</span></pre>
<h2>Arrow Functions fangen automatisch</h2>
<p><code class="inline">fn</code> braucht kein <code class="inline">use</code> – es sieht die umgebenden Variablen automatisch (nur lesend):</p>
<pre><span class="v">$mal</span> = <span class="k">fn</span>(<span class="v">$x</span>) => <span class="v">$x</span> * <span class="v">$faktor</span>;</pre>
<h2>by-reference einfangen</h2>
<p>Mit <code class="inline">&</code> teilt die Closure dieselbe Variable, statt eine Kopie zu nehmen:</p>
<pre><span class="v">$summe</span> = <span class="s">0</span>;
<span class="v">$add</span> = <span class="k">function</span>(<span class="v">$n</span>) <span class="k">use</span> (&<span class="v">$summe</span>) {
<span class="v">$summe</span> += <span class="v">$n</span>;
};
<span class="v">$add</span>(<span class="s">10</span>); <span class="v">$add</span>(<span class="s">5</span>);
<span class="k">echo</span> <span class="v">$summe</span>; <span class="c">// 15</span></pre>
<h2>$this binden</h2>
<p>Closures kennen das Objekt, in dem sie erzeugt wurden – mit <code class="inline">bindTo()</code> kannst du sie an ein anderes binden. Das nutzen Frameworks für Routing-Definitionen und Templating.</p>
<pre><span class="v">$closure</span> = <span class="k">function</span>() { <span class="k">return</span> <span class="v">$this</span>-><span class="v">name</span>; };
<span class="v">$gebunden</span> = <span class="t">Closure</span>::<span class="f">bind</span>(<span class="v">$closure</span>, <span class="v">$objekt</span>, <span class="t">Klasse</span>::<span class="k">class</span>);</pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Closure vs. Arrow Function</b><code class="inline">fn</code> ist kompakt und fängt automatisch ein, kann aber nur einen Ausdruck enthalten. Die längere <code class="inline">function() use(...)</code>-Form erlaubt mehrere Zeilen und das Einfangen per Referenz. Für einfache Callbacks <code class="inline">fn</code>, für alles andere die lange Form.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 30</span>
<h1>Attribute</h1>
</div>
<p class="lead">Attribute sind strukturierte Metadaten, die du direkt an Klassen, Methoden oder Eigenschaften heftest. Frameworks lesen sie aus, um Verhalten zu steuern – ganz ohne Konfigurationsdateien.</p>
<h2>Syntax</h2>
<p>Attribute stehen in <code class="inline">#[ ]</code> direkt über dem Element:</p>
<pre><span class="a">#[Route(<span class="s">"/users"</span>, methods: [<span class="s">"GET"</span>])]</span>
<span class="k">public function</span> <span class="f">liste</span>(): <span class="t">Response</span> { <span class="c">/* ... */</span> }</pre>
<h2>Ein eigenes Attribut</h2>
<p>Ein Attribut ist nichts weiter als eine Klasse mit dem Marker <code class="inline">#[Attribute]</code>:</p>
<pre><span class="a">#[Attribute(Attribute::TARGET_METHOD)]</span>
<span class="k">class</span> <span class="t">Route</span> {
<span class="k">public function</span> <span class="f">__construct</span>(
<span class="k">public</span> <span class="t">string</span> <span class="v">$pfad</span>,
<span class="k">public</span> <span class="t">array</span> <span class="v">$methods</span> = [<span class="s">"GET"</span>],
) {}
}</pre>
<h2>Attribute auslesen</h2>
<p>Über Reflection (nächstes Kapitel) liest ein Framework die Attribute zur Laufzeit aus:</p>
<pre><span class="v">$r</span> = <span class="k">new</span> <span class="t">ReflectionMethod</span>(<span class="v">$controller</span>, <span class="s">"liste"</span>);
<span class="k">foreach</span> (<span class="v">$r</span>-><span class="f">getAttributes</span>(<span class="t">Route</span>::<span class="k">class</span>) <span class="k">as</span> <span class="v">$attr</span>) {
<span class="v">$route</span> = <span class="v">$attr</span>-><span class="f">newInstance</span>();
<span class="k">echo</span> <span class="v">$route</span>-><span class="v">pfad</span>; <span class="c">// /users</span>
}</pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Wo du Attribute triffst</b>Symfony nutzt Attribute für Routing und Validierung, Doctrine für das Mapping von Klassen auf Datenbanktabellen, PHPUnit für Test-Markierungen. Du wirst sie also oft <i>nutzen</i>, bevor du eigene schreibst – und genau dafür ist es gut, das Prinzip zu verstehen.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 31</span>
<h1>Reflection</h1>
</div>
<p class="lead">Reflection erlaubt einem Programm, sich selbst zu untersuchen: Welche Methoden hat diese Klasse? Welche Parameter diese Funktion? Es ist die Magie hinter Dependency-Injection-Containern und Frameworks.</p>
<h2>Eine Klasse inspizieren</h2>
<pre><span class="v">$r</span> = <span class="k">new</span> <span class="t">ReflectionClass</span>(<span class="t">User</span>::<span class="k">class</span>);
<span class="k">echo</span> <span class="v">$r</span>-><span class="f">getName</span>(); <span class="c">// User</span>
<span class="k">foreach</span> (<span class="v">$r</span>-><span class="f">getMethods</span>() <span class="k">as</span> <span class="v">$m</span>) {
<span class="k">echo</span> <span class="v">$m</span>-><span class="f">getName</span>() . <span class="s">"\n"</span>;
}</pre>
<h2>Parameter einer Methode lesen</h2>
<p>So findet ein DI-Container heraus, welche Abhängigkeiten ein Konstruktor braucht:</p>
<pre><span class="v">$ctor</span> = (<span class="k">new</span> <span class="t">ReflectionClass</span>(<span class="t">Service</span>::<span class="k">class</span>))-><span class="f">getConstructor</span>();
<span class="k">foreach</span> (<span class="v">$ctor</span>-><span class="f">getParameters</span>() <span class="k">as</span> <span class="v">$p</span>) {
<span class="k">echo</span> <span class="v">$p</span>-><span class="f">getType</span>(); <span class="c">// der Typ des Parameters</span>
}</pre>
<h2>Objekte dynamisch erzeugen</h2>
<pre><span class="v">$obj</span> = (<span class="k">new</span> <span class="t">ReflectionClass</span>(<span class="v">$klassenName</span>))
-><span class="f">newInstanceArgs</span>(<span class="v">$argumente</span>);</pre>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>Reflection ist langsam & mächtig</b>Reflection umgeht <code class="inline">private</code> und ist deutlich langsamer als direkter Code. In Anwendungscode brauchst du es fast nie – es ist Framework-Handwerk. Gut zu verstehen, um zu wissen, <i>wie</i> deine Werkzeuge funktionieren; im Alltag aber selten selbst zu schreiben.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 32</span>
<h1>Namespaces im Detail</h1>
</div>
<p class="lead">Namespaces verhindern Namenskollisionen, wenn Code aus vielen Quellen zusammenkommt. Sie sind die Ordnerstruktur des Codes – und die Basis für Autoloading.</p>
<h2>Deklaration</h2>
<p>Ein Namespace steht als erste Anweisung der Datei:</p>
<pre><span class="t"><?php</span>
<span class="k">namespace</span> <span class="t">App\Service</span>;
<span class="k">class</span> <span class="t">Mailer</span> { <span class="c">/* voll: App\Service\Mailer */</span> }</pre>
<h2>use – Klassen importieren</h2>
<p>Statt überall den vollen Pfad zu schreiben, importierst du oben einmal:</p>
<pre><span class="k">use</span> <span class="t">App\Service\Mailer</span>;
<span class="k">use</span> <span class="t">App\Model\User</span>;
<span class="v">$m</span> = <span class="k">new</span> <span class="t">Mailer</span>(); <span class="c">// kurz statt voll qualifiziert</span></pre>
<h2>Aliasse bei Kollisionen</h2>
<p>Heißen zwei Klassen gleich, gibst du einer per <code class="inline">as</code> einen anderen Namen:</p>
<pre><span class="k">use</span> <span class="t">App\Pdf\Writer</span> <span class="k">as</span> <span class="t">PdfWriter</span>;
<span class="k">use</span> <span class="t">App\Csv\Writer</span> <span class="k">as</span> <span class="t">CsvWriter</span>;</pre>
<h2>Funktionen und Konstanten importieren</h2>
<pre><span class="k">use function</span> <span class="t">App\Helpers\slugify</span>;
<span class="k">use const</span> <span class="t">App\Config\VERSION</span>;</pre>
<h2>Der führende Backslash</h2>
<p>Ein <code class="inline">\</code> am Anfang meint „ab dem globalen Namespace". Innerhalb eines eigenen Namespaces brauchst du es, um auf eingebaute Klassen zuzugreifen:</p>
<pre><span class="k">namespace</span> <span class="t">App</span>;
<span class="v">$d</span> = <span class="k">new</span> <span class="t">\DateTime</span>(); <span class="c">// global, nicht App\DateTime</span></pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>PSR-4: Namespace = Ordner</b>Halte dich an die PSR-4-Konvention: Der Namespace spiegelt den Ordnerpfad. <code class="inline">App\Service\Mailer</code> liegt in <code class="inline">src/Service/Mailer.php</code>. Dann findet Composers Autoloader jede Klasse automatisch – du schreibst nie wieder ein <code class="inline">require</code> für Klassen.</div>
</div>
</section>
<section class="part-divider">
<div class="part-kicker">Teil 6</div>
<h1>Architektur & Patterns</h1>
<div class="part-desc">Wie man Code so strukturiert, dass er wachsen, sich ändern und testen lässt. SOLID, Dependency Injection, die wichtigsten Entwurfsmuster und Wertobjekte.</div>
<div class="part-chapters"><span>33 · SOLID-Prinzipien</span><span>34 · Dependency Injection</span><span>35 · Häufige Entwurfsmuster</span><span>36 · Wertobjekte & DTOs</span><span>37 · Fehlerbehandlung als Architektur</span></div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 33</span>
<h1>SOLID-Prinzipien</h1>
</div>
<p class="lead">SOLID sind fünf Faustregeln für Klassen, die langlebig und änderbar bleiben. Sie sind keine Gesetze, sondern Werkzeuge gegen den schleichenden Verfall großer Codebasen.</p>
<h2>S – Single Responsibility</h2>
<p>Eine Klasse sollte genau einen Grund haben, sich zu ändern. Eine Klasse, die Daten lädt <b>und</b> formatiert <b>und</b> verschickt, ändert sich aus drei Richtungen – das ist eine zu viel.</p>
<h2>O – Open/Closed</h2>
<p>Offen für Erweiterung, geschlossen für Änderung. Neues Verhalten fügst du durch neue Klassen hinzu, nicht durch das Aufbohren bestehender:</p>
<pre><span class="k">interface</span> <span class="t">Rabatt</span> {
<span class="k">public function</span> <span class="f">anwenden</span>(<span class="t">float</span> <span class="v">$preis</span>): <span class="t">float</span>;
}
<span class="c">// neuer Rabatt = neue Klasse, alter Code bleibt unberührt</span>
<span class="k">class</span> <span class="t">Weihnachtsrabatt</span> <span class="k">implements</span> <span class="t">Rabatt</span> { <span class="c">/* ... */</span> }</pre>
<h2>L – Liskov Substitution</h2>
<p>Eine Unterklasse muss überall einsetzbar sein, wo die Oberklasse erwartet wird – ohne Überraschungen. Wenn eine Unterklasse plötzlich Ausnahmen wirft, wo die Basis es nicht tut, ist das verletzt.</p>
<h2>I – Interface Segregation</h2>
<p>Lieber viele kleine, spezifische Interfaces als ein großes. Eine Klasse soll nicht Methoden implementieren müssen, die sie gar nicht braucht.</p>
<h2>D – Dependency Inversion</h2>
<p>Hänge von Abstraktionen ab, nicht von konkreten Klassen. Statt im Code <code class="inline">new MySQLConnection()</code> zu schreiben, nimm ein <code class="inline">Connection</code>-Interface entgegen – das ist die Brücke zu Dependency Injection.</p>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>SOLID mit Augenmaß</b>SOLID hilft, aber dogmatisch angewandt führt es zu einer Flut winziger Klassen. Die Prinzipien zahlen sich dort aus, wo sich Code oft ändert oder von mehreren Stellen genutzt wird. Bei kurzlebigem oder trivialem Code ist Pragmatismus die bessere Tugend.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 34</span>
<h1>Dependency Injection</h1>
</div>
<p class="lead">Dependency Injection (DI) heißt schlicht: Ein Objekt bekommt seine Abhängigkeiten von außen gereicht, statt sie selbst zu erzeugen. Das macht Code testbar und flexibel.</p>
<h2>Das Problem</h2>
<p>Erzeugt eine Klasse ihre Helfer selbst, ist sie fest verdrahtet – nicht austauschbar, nicht testbar:</p>
<pre><span class="k">class</span> <span class="t">Bestellung</span> {
<span class="k">public function</span> <span class="f">__construct</span>() {
<span class="v">$this</span>-><span class="v">mailer</span> = <span class="k">new</span> <span class="t">SmtpMailer</span>(); <span class="c">// fest verdrahtet</span>
}
}</pre>
<h2>Die Lösung: von außen reichen</h2>
<pre><span class="k">class</span> <span class="t">Bestellung</span> {
<span class="k">public function</span> <span class="f">__construct</span>(
<span class="k">private</span> <span class="t">Mailer</span> <span class="v">$mailer</span>, <span class="c">// Interface, injiziert</span>
) {}
}
<span class="c">// Produktion:</span>
<span class="k">new</span> <span class="t">Bestellung</span>(<span class="k">new</span> <span class="t">SmtpMailer</span>());
<span class="c">// Test:</span>
<span class="k">new</span> <span class="t">Bestellung</span>(<span class="k">new</span> <span class="t">FakeMailer</span>());</pre>
<h2>Der DI-Container</h2>
<p>Bei vielen verschachtelten Abhängigkeiten verdrahtest du nicht alles von Hand. Ein <b>Container</b> baut Objekte samt ihrer Abhängigkeiten automatisch zusammen:</p>
<pre><span class="v">$container</span>-><span class="f">get</span>(<span class="t">Bestellung</span>::<span class="k">class</span>);
<span class="c">// Container erkennt: braucht Mailer, baut SmtpMailer, ...</span></pre>
<p>Container lesen die nötigen Typen über Reflection (Kapitel 31) aus den Konstruktor-Signaturen. Genau deshalb sind Typdeklarationen so wichtig.</p>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Constructor Injection als Standard</b>Reiche Abhängigkeiten über den Konstruktor herein – nicht über Setter oder globale Zugriffe. Dann ist an der Signatur sofort ablesbar, was eine Klasse braucht, und ein unvollständig konfiguriertes Objekt kann gar nicht erst entstehen.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 35</span>
<h1>Häufige Entwurfsmuster</h1>
</div>
<p class="lead">Entwurfsmuster sind bewährte Lösungen für wiederkehrende Probleme. Du musst sie nicht auswendig kennen – aber die Namen helfen, über Architektur zu reden.</p>
<h2>Strategy</h2>
<p>Austauschbare Algorithmen hinter einem gemeinsamen Interface – das Open/Closed-Prinzip in Aktion:</p>
<pre><span class="k">interface</span> <span class="t">SortierStrategie</span> {
<span class="k">public function</span> <span class="f">sortiere</span>(<span class="t">array</span> <span class="v">$daten</span>): <span class="t">array</span>;
}
<span class="c">// QuickSort, MergeSort … jeweils eine Klasse, frei tauschbar</span></pre>
<h2>Factory</h2>
<p>Eine Methode, die Objekte erzeugt und die Entscheidung kapselt, <i>welche</i> konkrete Klasse:</p>
<pre><span class="k">class</span> <span class="t">ZahlungsFactory</span> {
<span class="k">public static function</span> <span class="f">erstelle</span>(<span class="t">string</span> <span class="v">$art</span>): <span class="t">Zahlung</span> {
<span class="k">return</span> <span class="k">match</span>(<span class="v">$art</span>) {
<span class="s">"paypal"</span> => <span class="k">new</span> <span class="t">PayPal</span>(),
<span class="s">"karte"</span> => <span class="k">new</span> <span class="t">Kreditkarte</span>(),
};
}
}</pre>
<h2>Observer</h2>
<p>Objekte abonnieren Ereignisse und werden benachrichtigt – die Basis von Event-Systemen:</p>
<pre><span class="k">interface</span> <span class="t">Beobachter</span> {
<span class="k">public function</span> <span class="f">benachrichtigt</span>(<span class="t">Ereignis</span> <span class="v">$e</span>): <span class="t">void</span>;
}</pre>
<h2>Repository</h2>
<p>Kapselt den Datenzugriff hinter einer sammlungsartigen Schnittstelle – der Code dahinter (SQL, API, Datei) bleibt verborgen:</p>
<pre><span class="k">interface</span> <span class="t">UserRepository</span> {
<span class="k">public function</span> <span class="f">finde</span>(<span class="t">int</span> <span class="v">$id</span>): <span class="t">?User</span>;
<span class="k">public function</span> <span class="f">speichere</span>(<span class="t">User</span> <span class="v">$u</span>): <span class="t">void</span>;
}</pre>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>Muster sind Mittel, kein Ziel</b>Der häufigste Fehler mit Entwurfsmustern ist, sie überall einzusetzen, weil man sie gerade gelernt hat. Ein Muster ist eine Antwort auf ein konkretes Problem. Hast du das Problem nicht, brauchst du das Muster nicht – einfacher Code schlägt clevere Architektur ohne Anlass.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 36</span>
<h1>Wertobjekte & DTOs</h1>
</div>
<p class="lead">Statt nackte Strings und Zahlen durch den Code zu reichen, kapselst du Bedeutung in kleine Typen. Das macht Fehler unmöglich, die sonst erst zur Laufzeit auffallen.</p>
<h2>Das Problem mit Primitiven</h2>
<pre><span class="k">function</span> <span class="f">versende</span>(<span class="t">string</span> <span class="v">$email</span>): <span class="t">void</span> { <span class="c">/* ... */</span> }
<span class="f">versende</span>(<span class="s">"kein-email"</span>); <span class="c">// kompiliert, kracht erst später</span></pre>
<h2>Ein Wertobjekt</h2>
<p>Validiere einmal bei der Erzeugung – danach ist die Gültigkeit garantiert. <code class="inline">readonly</code> macht es unveränderlich:</p>
<pre><span class="k">final</span> <span class="k">readonly</span> <span class="k">class</span> <span class="t">Email</span> {
<span class="k">public function</span> <span class="f">__construct</span>(<span class="k">public</span> <span class="t">string</span> <span class="v">$wert</span>) {
<span class="k">if</span> (!<span class="k">filter_var</span>(<span class="v">$wert</span>, <span class="t">FILTER_VALIDATE_EMAIL</span>)) {
<span class="k">throw new</span> <span class="t">InvalidArgumentException</span>(<span class="s">"Ungültige E-Mail"</span>);
}
}
}
<span class="k">function</span> <span class="f">versende</span>(<span class="t">Email</span> <span class="v">$email</span>): <span class="t">void</span> { <span class="c">/* immer gültig */</span> }</pre>
<h2>DTO – Data Transfer Object</h2>
<p>Ein DTO bündelt zusammengehörige Daten in einem typisierten Objekt – etwa Formulareingaben oder API-Antworten. Kein Verhalten, nur Struktur:</p>
<pre><span class="k">final</span> <span class="k">readonly</span> <span class="k">class</span> <span class="t">RegistrierDaten</span> {
<span class="k">public function</span> <span class="f">__construct</span>(
<span class="k">public</span> <span class="t">string</span> <span class="v">$name</span>,
<span class="k">public</span> <span class="t">Email</span> <span class="v">$email</span>,
<span class="k">public</span> <span class="t">int</span> <span class="v">$alter</span>,
) {}
}</pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Primitive Obsession bekämpfen</b>Das Durchreichen von rohen Strings und Ints für Dinge mit Bedeutung (E-Mail, Geldbetrag, ID) nennt man „Primitive Obsession”. Ein kleines Wertobjekt kostet wenige Zeilen, verlagert aber eine ganze Klasse von Fehlern von der Laufzeit in den Moment der Erzeugung.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 37</span>
<h1>Fehlerbehandlung als Architektur</h1>
</div>
<p class="lead">Wie eine Anwendung mit Fehlern umgeht, ist eine Architektur-Entscheidung. Gut gemacht, bleiben Fehler nachvollziehbar und die Geschäftslogik sauber.</p>
<h2>Eigene Exception-Typen</h2>
<p>Spezifische Exceptions erlauben gezieltes Abfangen und sprechende Fehler:</p>
<pre><span class="k">class</span> <span class="t">KontoUeberzogen</span> <span class="k">extends</span> <span class="t">DomainException</span> {
<span class="k">public static function</span> <span class="f">bei</span>(<span class="t">float</span> <span class="v">$fehlbetrag</span>): <span class="k">self</span> {
<span class="k">return new</span> <span class="k">self</span>(<span class="s">"Es fehlen $fehlbetrag €"</span>);
}
}</pre>
<h2>Wo fangen, wo durchreichen?</h2>
<p>Eine bewährte Regel: Fange Exceptions möglichst weit oben – an der „Grenze" der Anwendung (Controller, CLI-Einstieg). Die Geschäftslogik <i>wirft</i> nur, sie behandelt nicht. So bleibt sie frei von <code class="inline">try/catch</code>-Rauschen:</p>
<pre><span class="c">// Controller – die eine zentrale Stelle</span>
<span class="k">try</span> {
<span class="v">$service</span>-><span class="f">verarbeite</span>(<span class="v">$daten</span>);
} <span class="k">catch</span> (<span class="t">DomainException</span> <span class="v">$e</span>) {
<span class="k">return</span> <span class="f">fehlerSeite</span>(<span class="v">$e</span>-><span class="f">getMessage</span>());
}</pre>
<h2>Result statt Exception</h2>
<p>Für erwartbare Fehlschläge (Validierung) sind Exceptions manchmal zu schwer. Eine Alternative ist ein Ergebnis-Objekt, das Erfolg oder Fehler trägt:</p>
<pre><span class="k">if</span> (<span class="v">$ergebnis</span>-><span class="f">istErfolg</span>()) {
<span class="v">$wert</span> = <span class="v">$ergebnis</span>-><span class="f">wert</span>();
} <span class="k">else</span> {
<span class="k">echo</span> <span class="v">$ergebnis</span>-><span class="f">fehler</span>();
}</pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Exceptions für Ausnahmen</b>Der Name sagt es: Exceptions sind für <i>Ausnahmen</i> gedacht – Dinge, die nicht im normalen Ablauf liegen. Ein fehlgeschlagenes Login ist erwartbar und gehört eher als Ergebnis modelliert; eine verlorene Datenbankverbindung ist eine echte Ausnahme. Diese Unterscheidung hält den Kontrollfluss klar.</div>
</div>
</section>
<section class="part-divider">
<div class="part-kicker">Teil 7</div>
<h1>Qualität & Profi-Werkzeug</h1>
<div class="part-desc">Was professionellen Code von Bastelei trennt: automatisierte Tests, statische Analyse, einheitlicher Stil und systematisches Debugging.</div>
<div class="part-chapters"><span>38 · Testen mit PHPUnit</span><span>39 · Statische Analyse</span><span>40 · Code-Style & Tooling</span><span>41 · Debugging & Xdebug</span></div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 38</span>
<h1>Testen mit PHPUnit</h1>
</div>
<p class="lead">Automatisierte Tests prüfen bei jeder Änderung, ob dein Code noch das Richtige tut. PHPUnit ist der De-facto-Standard dafür in der PHP-Welt.</p>
<h2>Installation</h2>
<pre>composer require --dev phpunit/phpunit</pre>
<h2>Ein erster Test</h2>
<p>Ein Test ist eine Methode, die etwas ausführt und mit <code class="inline">assert</code>-Aufrufen das erwartete Ergebnis prüft:</p>
<pre><span class="k">use</span> <span class="t">PHPUnit\Framework\TestCase</span>;
<span class="k">final class</span> <span class="t">RechnerTest</span> <span class="k">extends</span> <span class="t">TestCase</span> {
<span class="k">public function</span> <span class="f">testAddition</span>(): <span class="t">void</span> {
<span class="v">$r</span> = <span class="k">new</span> <span class="t">Rechner</span>();
<span class="v">$this</span>-><span class="f">assertSame</span>(<span class="s">5</span>, <span class="v">$r</span>-><span class="f">addiere</span>(<span class="s">2</span>, <span class="s">3</span>));
}
}</pre>
<p>Ausführen:</p>
<pre>vendor/bin/phpunit
<span class="c"># OK (1 test, 1 assertion)</span></pre>
<h2>Die wichtigsten Assertions</h2>
<table>
<tr><th>Assertion</th><th>Prüft</th></tr>
<tr><td><code>assertSame($a, $b)</code></td><td>identisch (===)</td></tr>
<tr><td><code>assertEquals($a, $b)</code></td><td>gleich (==)</td></tr>
<tr><td><code>assertTrue / assertFalse</code></td><td>Wahrheitswert</td></tr>
<tr><td><code>assertNull</code></td><td>ist null</td></tr>
<tr><td><code>assertCount(3, $arr)</code></td><td>Anzahl Elemente</td></tr>
<tr><td><code>expectException(...)</code></td><td>Fehler wird geworfen</td></tr>
</table>
<h2>Data Provider – ein Test, viele Fälle</h2>
<p>Statt fünf fast gleiche Tests zu schreiben, fütterst du einen Test mit Datensätzen:</p>
<pre><span class="a">#[DataProvider(<span class="s">"zahlen"</span>)]</span>
<span class="k">public function</span> <span class="f">testQuadrat</span>(<span class="t">int</span> <span class="v">$ein</span>, <span class="t">int</span> <span class="v">$aus</span>): <span class="t">void</span> {
<span class="v">$this</span>-><span class="f">assertSame</span>(<span class="v">$aus</span>, <span class="f">quadrat</span>(<span class="v">$ein</span>));
}
<span class="k">public static function</span> <span class="f">zahlen</span>(): <span class="t">array</span> {
<span class="k">return</span> [[<span class="s">2</span>, <span class="s">4</span>], [<span class="s">3</span>, <span class="s">9</span>], [<span class="s">5</span>, <span class="s">25</span>]];
}</pre>
<h2>Mocks – Abhängigkeiten ersetzen</h2>
<p>Um eine Klasse isoliert zu testen, ersetzt du ihre Abhängigkeiten durch kontrollierte Attrappen:</p>
<pre><span class="v">$mailer</span> = <span class="v">$this</span>-><span class="f">createMock</span>(<span class="t">Mailer</span>::<span class="k">class</span>);
<span class="v">$mailer</span>-><span class="f">expects</span>(<span class="v">$this</span>-><span class="f">once</span>())-><span class="f">method</span>(<span class="s">"sende"</span>);</pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Erst der Test, dann der Fehler</b>Wenn du einen Bug findest, schreib zuerst einen Test, der ihn reproduziert – er schlägt fehl. Dann reparierst du den Code, bis der Test grün ist. So weißt du sicher, dass der Fehler weg ist und nie unbemerkt zurückkehrt.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 39</span>
<h1>Statische Analyse</h1>
</div>
<p class="lead">Statische Analyse findet Fehler, ohne den Code auszuführen – allein durch das Lesen. Werkzeuge wie PHPStan und Psalm fangen ganze Fehlerklassen ab, bevor sie je zur Laufzeit auftreten.</p>
<h2>Was sie finden</h2>
<ul>
<li>Aufrufe nicht existierender Methoden oder Eigenschaften</li>
<li>Typfehler – ein <code class="inline">string</code>, wo ein <code class="inline">int</code> erwartet wird</li>
<li><code class="inline">null</code>-Zugriffe, die zur Laufzeit krachen würden</li>
<li>toter Code, unerreichbare Zweige</li>
</ul>
<h2>PHPStan einsetzen</h2>
<pre>composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse src --level 6</pre>
<p>Die <b>Level</b> reichen von 0 (locker) bis 10 (sehr streng). Ein guter Weg: niedrig starten und Stufe für Stufe erhöhen, während du die gemeldeten Probleme abarbeitest.</p>
<h2>Generics über PHPDoc</h2>
<p>Hier zahlt sich das Generics-Denken aus Kapitel 27 aus. PHPStan versteht die Annotationen und prüft sie:</p>
<pre><span class="c">/** @return list<User> */</span>
<span class="k">public function</span> <span class="f">alle</span>(): <span class="t">array</span> { <span class="c">/* ... */</span> }</pre>
<h2>Baseline für Altprojekte</h2>
<p>In bestehendem Code meldet PHPStan oft hunderte Probleme. Eine <b>Baseline</b> friert die aktuellen Funde ein, sodass nur <i>neue</i> Fehler auffallen:</p>
<pre>vendor/bin/phpstan analyse --generate-baseline</pre>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Statische Analyse in CI</b>Lass PHPStan automatisch bei jedem Push laufen (Continuous Integration). Dann kommt fehlerhafter Code gar nicht erst in den Hauptzweig. In Kombination mit <code class="inline">declare(strict_types=1)</code> und Tests bildet das ein engmaschiges Sicherheitsnetz.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 40</span>
<h1>Code-Style & Tooling</h1>
</div>
<p class="lead">Einheitlicher Stil macht Code lesbar und beendet sinnlose Diskussionen über Klammern und Einrückung. Werkzeuge erledigen die Formatierung automatisch.</p>
<h2>PSR-12 – der Standard</h2>
<p>Die PHP-Community hat sich auf einen gemeinsamen Stil geeinigt: <b>PSR-12</b>. Er regelt Einrückung (4 Leerzeichen), Klammersetzung, Import-Reihenfolge und mehr. Du musst ihn nicht auswendig lernen – Werkzeuge setzen ihn durch.</p>
<h2>PHP-CS-Fixer</h2>
<p>Formatiert deinen Code automatisch nach festgelegten Regeln:</p>
<pre>composer require --dev friendsofphp/php-cs-fixer
vendor/bin/php-cs-fixer fix src</pre>
<h2>Composer-Skripte als Abkürzung</h2>
<p>Häufige Befehle bündelst du in <code class="inline">composer.json</code> – ein Befehl statt vieler:</p>
<pre><span class="s">{
"scripts": {
"check": [
"@php vendor/bin/phpunit",
"@php vendor/bin/phpstan analyse src",
"@php vendor/bin/php-cs-fixer fix --dry-run"
]
}
}</span></pre>
<p>Danach genügt <code class="inline">composer check</code>, um Tests, Analyse und Stilprüfung in einem Rutsch laufen zu lassen.</p>
<h2>Der typische Werkzeugkasten</h2>
<table>
<tr><th>Aufgabe</th><th>Werkzeug</th></tr>
<tr><td>Pakete</td><td>Composer</td></tr>
<tr><td>Tests</td><td>PHPUnit / Pest</td></tr>
<tr><td>Statische Analyse</td><td>PHPStan / Psalm</td></tr>
<tr><td>Formatierung</td><td>PHP-CS-Fixer / PHPCS</td></tr>
<tr><td>Debugging</td><td>Xdebug</td></tr>
</table>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Stil ist Konvention, nicht Geschmack</b>Welcher Stil „besser” ist, spielt kaum eine Rolle – wichtig ist, dass ein Projekt <i>einen</i> hat und ihn automatisch durchsetzt. Mit einem Formatierer im Editor-Speichern-Hook denkst du nie wieder über Einrückung nach.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 41</span>
<h1>Debugging & Xdebug</h1>
</div>
<p class="lead">Früher oder später läuft Code anders als gedacht. Statt mit <code class="inline">echo</code> zu raten, schaust du mit einem Debugger Schritt für Schritt zu, was wirklich passiert.</p>
<h2>Der schnelle Weg: var_dump & dd</h2>
<p>Für einen kurzen Blick reicht oft eine Ausgabe. <code class="inline">var_dump</code> zeigt Wert und Typ:</p>
<pre><span class="k">var_dump</span>(<span class="v">$daten</span>);
<span class="c">// in Frameworks oft: dump($daten) oder dd($daten) (dump and die)</span></pre>
<h2>Xdebug – der richtige Debugger</h2>
<p>Xdebug ist eine PHP-Erweiterung. Einmal eingerichtet, kannst du im Editor <b>Breakpoints</b> setzen: Das Programm hält dort an, und du untersuchst alle Variablen live.</p>
<pre><span class="c"># Installation (Beispiel Ubuntu)</span>
sudo apt install php-xdebug</pre>
<p>Im Editor (z. B. PHPStorm oder VS Code) aktivierst du „Listen for debug connections", setzt einen Breakpoint per Klick an den Zeilenrand und lädst die Seite. Der Ablauf stoppt – du siehst den kompletten Aufruf-Stack.</p>
<h2>Die Werkzeuge im Debugger</h2>
<table>
<tr><th>Aktion</th><th>Bedeutung</th></tr>
<tr><td>Step Over</td><td>nächste Zeile, Funktionen am Stück</td></tr>
<tr><td>Step Into</td><td>in die aufgerufene Funktion hinein</td></tr>
<tr><td>Step Out</td><td>aktuelle Funktion zu Ende</td></tr>
<tr><td>Watch</td><td>einen Ausdruck dauerhaft beobachten</td></tr>
</table>
<h2>Fehler sichtbar machen</h2>
<p>In der Entwicklung sollten alle Fehler angezeigt werden – verstecke sie nie still:</p>
<pre><span class="k">error_reporting</span>(<span class="t">E_ALL</span>);
<span class="k">ini_set</span>(<span class="s">"display_errors"</span>, <span class="s">"1"</span>);
<span class="c">// In Produktion: display_errors aus, dafür ins Log schreiben</span></pre>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>echo-Debugging hat Grenzen</b>Mit eingestreuten <code class="inline">var_dump</code>-Zeilen kommt man weit – aber bei verschachtelten Aufrufen oder Schleifen verliert man schnell den Überblick. Die halbe Stunde, Xdebug einmal einzurichten, spart über die Zeit viele Stunden Rätselraten.</div>
</div>
</section>
<section class="part-divider">
<div class="part-kicker">Teil 8</div>
<h1>Experten & Nischen</h1>
<div class="part-desc">Die Themen jenseits des Alltags: Performance herausholen, Speicher verstehen, Prozesse und Fibers, robuste CLI-Programme und die Sicherheits-Klassiker.</div>
<div class="part-chapters"><span>42 · Performance & OPcache</span><span>43 · Speicher & Referenzen</span><span>44 · Prozesse, FFI & Fibers</span><span>45 · CLI-Programme bauen</span><span>46 · Sicherheit: die Klassiker</span></div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 42</span>
<h1>Performance & OPcache</h1>
</div>
<p class="lead">PHP ist schnell – wenn man es lässt. Die größten Hebel liegen selten im Mikro-Tuning einzelner Zeilen, sondern in Caching, weniger Arbeit und dem richtigen Werkzeug.</p>
<h2>OPcache – kompilierten Code wiederverwenden</h2>
<p>Normalerweise übersetzt PHP jede Datei bei jedem Aufruf neu. OPcache speichert das Übersetzungsergebnis im Speicher – ein gewaltiger Gewinn, fast geschenkt:</p>
<pre><span class="c">; php.ini</span>
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000</pre>
<p>In Produktion ist OPcache praktisch Pflicht. Es ist der wirkungsvollste einzelne Performance-Schalter.</p>
<h2>Messen statt raten</h2>
<p>Optimiere nie nach Bauchgefühl. Ein <b>Profiler</b> (Xdebug, Blackfire, SPX) zeigt, wo die Zeit wirklich verbraucht wird – oft an völlig anderen Stellen als vermutet:</p>
<pre><span class="v">$start</span> = <span class="k">hrtime</span>(<span class="k">true</span>);
<span class="c">// ... Code ...</span>
<span class="v">$ms</span> = (<span class="k">hrtime</span>(<span class="k">true</span>) - <span class="v">$start</span>) / <span class="s">1_000_000</span>;</pre>
<h2>Die häufigste Bremse: N+1</h2>
<p>Ein klassischer Datenbank-Fehler: In einer Schleife für jeden Datensatz eine eigene Abfrage. 100 Nutzer = 101 Abfragen statt einer. Lade verwandte Daten gebündelt.</p>
<h2>JIT – mit Augenmaß</h2>
<p>Seit PHP 8 gibt es einen <b>JIT-Compiler</b>. Er beschleunigt rechenintensive Aufgaben (Bildverarbeitung, Mathematik) spürbar, bringt bei typischem Web-Code mit viel I/O aber kaum etwas.</p>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Reihenfolge der Optimierung</b>Erst OPcache und einen Profiler einschalten, dann die teuersten Stellen finden, dann gezielt verbessern – meist sind es Datenbankabfragen oder fehlendes Caching. Mikro-Optimierungen einzelner Funktionen lohnen fast nie und machen den Code schwerer lesbar.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 43</span>
<h1>Speicher & Referenzen</h1>
</div>
<p class="lead">PHP verwaltet Speicher automatisch, aber zu verstehen, wie Werte kopiert und freigegeben werden, hilft bei großen Datenmengen und kniffligen Bugs.</p>
<h2>Copy-on-Write</h2>
<p>Weist du eine Variable einer anderen zu, kopiert PHP den Wert nicht sofort – erst wenn einer der beiden geändert wird. Das spart Speicher, ohne dass du etwas tun musst:</p>
<pre><span class="v">$a</span> = <span class="k">range</span>(<span class="s">1</span>, <span class="s">1_000_000</span>);
<span class="v">$b</span> = <span class="v">$a</span>; <span class="c">// noch keine Kopie, beide teilen sich</span>
<span class="v">$b</span>[<span class="s">0</span>] = <span class="s">99</span>; <span class="c">// jetzt erst wird kopiert</span></pre>
<h2>Referenzen mit &</h2>
<p>Eine Referenz ist ein zweiter Name für dieselbe Variable. Änderungen wirken auf beide:</p>
<pre><span class="v">$a</span> = <span class="s">1</span>;
<span class="v">$b</span> = &<span class="v">$a</span>; <span class="c">// $b ist $a</span>
<span class="v">$b</span> = <span class="s">99</span>;
<span class="k">echo</span> <span class="v">$a</span>; <span class="c">// 99</span></pre>
<h2>Garbage Collection</h2>
<p>PHP zählt, wie viele Namen auf einen Wert zeigen. Sinkt der Zähler auf null, wird der Speicher frei. Zirkuläre Referenzen (A zeigt auf B, B auf A) fängt ein zusätzlicher Collector ab.</p>
<h2>Speicher im Blick behalten</h2>
<pre><span class="k">echo</span> <span class="k">memory_get_usage</span>(<span class="k">true</span>); <span class="c">// aktuell</span>
<span class="k">echo</span> <span class="k">memory_get_peak_usage</span>(<span class="k">true</span>); <span class="c">// Höchststand</span></pre>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>Referenzen sind selten nötig</b>Anfänger greifen oft zu <code class="inline">&</code>, um „Performance zu sparen” – dank Copy-on-Write ist das fast nie nötig und führt zu schwer auffindbaren Bugs, wenn unerwartet eine entfernte Variable mitverändert wird. Nutze Referenzen nur, wenn du sie wirklich brauchst (etwa <code class="inline">sort()</code>, das sein Argument verändert).</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 44</span>
<h1>Prozesse, FFI & Fibers</h1>
</div>
<p class="lead">Drei fortgeschrittene Wege, über die übliche Request-Verarbeitung hinauszugehen: externe Programme starten, C-Bibliotheken einbinden und kooperatives Multitasking.</p>
<h2>Externe Programme starten</h2>
<p>Manchmal ist das beste Werkzeug ein anderes Programm. <code class="inline">proc_open</code> gibt dir volle Kontrolle über dessen Ein- und Ausgabe:</p>
<pre><span class="v">$out</span> = <span class="k">shell_exec</span>(<span class="s">"git rev-parse HEAD"</span>);
<span class="c">// für einfache Fälle; bei Nutzereingaben unbedingt escapen!</span></pre>
<h2>FFI – C-Bibliotheken aufrufen</h2>
<p>Mit der Foreign Function Interface bindest du vorhandene C-Bibliotheken direkt ein, ohne eine PHP-Erweiterung zu schreiben:</p>
<pre><span class="v">$ffi</span> = <span class="t">FFI</span>::<span class="f">cdef</span>(
<span class="s">"int abs(int);"</span>,
<span class="s">"libc.so.6"</span>
);
<span class="k">echo</span> <span class="v">$ffi</span>-><span class="f">abs</span>(-<span class="s">42</span>); <span class="c">// 42</span></pre>
<p>FFI ist ein Nischenwerkzeug – nützlich, um Spezialbibliotheken anzuzapfen, aber selten im Alltag.</p>
<h2>Fibers – kooperatives Multitasking</h2>
<p>Seit PHP 8.1 gibt es <b>Fibers</b>: Funktionen, die sich selbst pausieren und später fortsetzen können. Sie sind die Grundlage moderner asynchroner Frameworks wie ReactPHP und Amp:</p>
<pre><span class="v">$fiber</span> = <span class="k">new</span> <span class="t">Fiber</span>(<span class="k">function</span>() {
<span class="v">$wert</span> = <span class="t">Fiber</span>::<span class="f">suspend</span>(<span class="s">"pausiert"</span>);
<span class="k">echo</span> <span class="s">"weiter mit $wert"</span>;
});
<span class="v">$x</span> = <span class="v">$fiber</span>-><span class="f">start</span>(); <span class="c">// "pausiert"</span>
<span class="v">$fiber</span>-><span class="f">resume</span>(<span class="s">"Daten"</span>); <span class="c">// weiter mit Daten</span></pre>
<div class="callout note">
<div class="callout-icon">i</div>
<div class="callout-body"><b>Selten gebraucht, gut zu kennen</b>Fibers nutzt du fast nie direkt – die asynchronen Frameworks kapseln sie. Aber zu wissen, dass PHP kooperatives Multitasking beherrscht, hilft beim Verständnis, wie etwa Swoole oder Amp Tausende gleichzeitige Verbindungen in einem Prozess bewältigen.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 45</span>
<h1>CLI-Programme bauen</h1>
</div>
<p class="lead">PHP ist nicht nur für Webseiten da. Kommandozeilen-Programme – für Wartung, Datenimport, Cronjobs – sind ein wichtiger Einsatzbereich.</p>
<h2>Argumente lesen</h2>
<p>Das Array <code class="inline">$argv</code> enthält die übergebenen Argumente, <code class="inline">$argc</code> ihre Anzahl:</p>
<pre><span class="c">// php import.php datei.csv --dry-run</span>
<span class="k">echo</span> <span class="v">$argv</span>[<span class="s">1</span>]; <span class="c">// datei.csv</span></pre>
<h2>Ein-/Ausgabe-Ströme</h2>
<p>CLI-Programme nutzen drei Standard-Kanäle. Fehler gehören nach <code class="inline">STDERR</code>, damit sie sich von der normalen Ausgabe trennen lassen:</p>
<pre><span class="k">fwrite</span>(<span class="t">STDOUT</span>, <span class="s">"Fertig\n"</span>);
<span class="k">fwrite</span>(<span class="t">STDERR</span>, <span class="s">"Warnung!\n"</span>);
<span class="v">$eingabe</span> = <span class="k">fgets</span>(<span class="t">STDIN</span>); <span class="c">// vom Nutzer lesen</span></pre>
<h2>Exit-Codes</h2>
<p>Ein Programm meldet Erfolg oder Misserfolg über seinen Rückgabewert: 0 = alles gut, alles andere = Fehler. Skripte und CI verlassen sich darauf:</p>
<pre><span class="k">if</span> (<span class="v">$fehler</span>) {
<span class="k">fwrite</span>(<span class="t">STDERR</span>, <span class="s">"Abbruch\n"</span>);
<span class="k">exit</span>(<span class="s">1</span>);
}
<span class="k">exit</span>(<span class="s">0</span>);</pre>
<h2>Komfort mit Symfony Console</h2>
<p>Für ernsthafte CLI-Werkzeuge lohnt eine Bibliothek. Symfony Console liefert Argument-Parsing, Hilfetexte, Farben, Fortschrittsbalken und Tabellen:</p>
<pre>composer require symfony/console</pre>
<p>Damit definierst du Befehle als Klassen, bekommst <code class="inline">--help</code> automatisch und eine saubere Struktur für wachsende Werkzeuge.</p>
<div class="callout tip">
<div class="callout-icon">✓</div>
<div class="callout-body"><b>Shebang für direkte Ausführung</b>Beginnt dein Skript mit <code class="inline">#!/usr/bin/env php</code> und ist es ausführbar (<code class="inline">chmod +x</code>), kannst du es ohne vorangestelltes <code class="inline">php</code> direkt aufrufen – wie jedes andere Kommandozeilen-Programm.</div>
</div>
</section>
<section class="chapter">
<div class="chapter-head">
<span class="chapter-num">Kapitel 46</span>
<h1>Sicherheit: die Klassiker</h1>
</div>
<p class="lead">Die meisten Sicherheitslücken sind seit Jahren dieselben – und seit Jahren vermeidbar. Wer diese Klassiker kennt, schließt die gefährlichsten Türen.</p>
<h2>SQL-Injection</h2>
<p>Niemals Nutzereingaben in SQL einbauen. <b>Prepared Statements</b> trennen Befehl und Daten – die Eingabe kann nie als Code interpretiert werden:</p>
<pre><span class="c">// FALSCH – angreifbar</span>
<span class="v">$db</span>-><span class="f">query</span>(<span class="s">"SELECT * FROM users WHERE id = $id"</span>);
<span class="c">// RICHTIG – Prepared Statement</span>
<span class="v">$stmt</span> = <span class="v">$db</span>-><span class="f">prepare</span>(<span class="s">"SELECT * FROM users WHERE id = ?"</span>);
<span class="v">$stmt</span>-><span class="f">execute</span>([<span class="v">$id</span>]);</pre>
<h2>XSS – Cross-Site Scripting</h2>
<p>Gibst du Nutzereingaben in HTML aus, ohne sie zu maskieren, kann jemand Schadcode einschleusen. <code class="inline">htmlspecialchars</code> entschärft das:</p>
<pre><span class="k">echo</span> <span class="k">htmlspecialchars</span>(<span class="v">$kommentar</span>, <span class="t">ENT_QUOTES</span>);</pre>
<h2>CSRF – gefälschte Anfragen</h2>
<p>Ein Angreifer bringt den Browser eines eingeloggten Nutzers dazu, ungewollt Aktionen auszuführen. Schutz: ein geheimes, pro Formular einzigartiges <b>Token</b>, das der Server prüft.</p>
<h2>Passwörter richtig speichern</h2>
<p>Niemals im Klartext, niemals mit MD5 oder SHA1. PHP bringt die richtige Funktion mit – sie hasht, salzt und passt die Stärke automatisch an:</p>
<pre><span class="v">$hash</span> = <span class="k">password_hash</span>(<span class="v">$passwort</span>, <span class="t">PASSWORD_DEFAULT</span>);
<span class="k">if</span> (<span class="k">password_verify</span>(<span class="v">$eingabe</span>, <span class="v">$hash</span>)) {
<span class="c">// Login korrekt</span>
}</pre>
<h2>Grundregeln</h2>
<table>
<tr><th>Regel</th><th>Warum</th></tr>
<tr><td>Eingaben validieren</td><td>traue keiner Quelle von außen</td></tr>
<tr><td>Ausgaben maskieren</td><td>verhindert XSS</td></tr>
<tr><td>Prepared Statements</td><td>verhindert SQL-Injection</td></tr>
<tr><td><code>password_hash</code></td><td>sichere Passwörter</td></tr>
<tr><td>Abhängigkeiten aktuell halten</td><td><code>composer audit</code></td></tr>
</table>
<div class="callout warn">
<div class="callout-icon">!</div>
<div class="callout-body"><b>Sicherheit ist nicht optional</b>Validiere alles, was von außen kommt – Formulare, URLs, Header, hochgeladene Dateien. Die Faustregel lautet: niemals Nutzereingaben vertrauen. <code class="inline">composer audit</code> meldet zudem bekannte Lücken in deinen Abhängigkeiten – führe es regelmäßig aus.</div>
</div>
</section>
</body>
</html>