Typsystem
<?php
declare(strict_types=1);
function f(int|string $id, ?array $optionen = null, mixed $beliebig = null): string|int|null { return $id; }
function wirf(): never { throw new Exception("nie zurück"); }
interface A {} interface B {}
class AB implements A, B {}
function schnitt(A&B $x): string { return $x::class; } // Intersection Types (8.1)
echo schnitt(new AB()), " ", f("x"), "\n";
class Mensch
{
public function __construct(
public readonly string $name,
public readonly int $alter = 0,
private array $tags = [],
) {}
public function mit(string $name): static
{
return new static($name, $this->alter, $this->tags); // "wither"-Muster für unveränderliche Objekte
}
}
$m = new Mensch("Mia", alter: 17);
echo $m->mit("Tom")->name, " ", $m->name, "\n";AB x Tom Mia
match, Null-Safe und weitere Neuerungen
<?php
class Adresse { public function __construct(public ?string $ort = null) {} }
class Kunde { public function __construct(public ?Adresse $adresse = null) {} }
$k1 = new Kunde(new Adresse("Berlin"));
$k2 = new Kunde();
echo $k1->adresse?->ort ?? "-", " ", $k2->adresse?->ort ?? "-", "\n"; // Nullsafe-Operator ?->
echo str_contains("Hallo", "all") ? "ja" : "nein", " ", 1_000_000, " ", 0o17, "\n"; // 0o: Oktal-Schreibweise (8.1)
$liste = [...[1, 2], ...["a" => "x"], 3]; // Spread mit String-Keys (8.1)
print_r($liste);
function benannt(int $a = 1, int $b = 2, int $c = 3): string { return "$a$b$c"; }
echo benannt(c: 9), " ", benannt(1, c: 5), "\n";Berlin -
ja 1000000 15
Array
(
[0] => 1
[1] => 2
[a] => x
[2] => 3
)
129 125Attribute
Attribute (PHP 8) sind strukturierte Metadaten, die Frameworks per Reflection auslesen:
<?php
#[Attribute(Attribute::TARGET_PROPERTY)]
class Laenge
{
public function __construct(public int $min = 0, public int $max = PHP_INT_MAX) {}
}
class Registrierung
{
#[Laenge(min: 3, max: 10)]
public string $name = "ab";
}
function validiere(object $obj): array
{
$fehler = [];
foreach ((new ReflectionClass($obj))->getProperties() as $prop) {
foreach ($prop->getAttributes(Laenge::class) as $attr) {
$regel = $attr->newInstance();
$len = strlen((string) $prop->getValue($obj));
if ($len < $regel->min || $len > $regel->max) {
$fehler[] = "{$prop->getName()}: Länge {$len} nicht in {$regel->min}..{$regel->max}";
}
}
}
return $fehler;
}
print_r(validiere(new Registrierung()));Array
(
[0] => name: Länge 2 nicht in 3..10
)First-class Callables, Closures und Generatoren
<?php
$upper = strtoupper(...);
class Rechner { public function doppelt(int $x): int { return $x * 2; } public static function plus1(int $x): int { return $x + 1; } }
$r = new Rechner();
$d = $r->doppelt(...);
$p = Rechner::plus1(...);
echo $upper("a"), $d(4), $p(4), "\n";
$pipeline = array_reduce([fn($x) => $x + 1, fn($x) => $x * 10, $d], fn($carry, $f) => fn($x) => $f($carry($x)), fn($x) => $x);
echo $pipeline(1), "\n";
function gen_lines(string $text): Generator { foreach (explode("\n", $text) as $i => $l) yield $i + 1 => $l; return "fertig"; }
$g = gen_lines("a\nb");
foreach ($g as $nr => $zeile) echo "$nr:$zeile ";
echo $g->getReturn(), "\n";
function mit_yield_from(): Generator { yield 1; yield from [2, 3]; yield 4; }
echo implode(",", iterator_to_array(mit_yield_from(), false)), "\n";A85 40 1:a 2:b fertig 1,2,3,4
Weitere eingebaute Klassen und Funktionen
<?php
$s = new SplStack(); $s->push(1); $s->push(2);
echo $s->pop(), $s->top(), " ";
$q = new SplQueue(); $q->enqueue("a"); $q->enqueue("b");
echo $q->dequeue(), count($q), " ";
$h = new SplMinHeap(); foreach ([5, 1, 3] as $x) $h->insert($x);
echo $h->extract(), " ";
$o = new SplObjectStorage(); $obj = new stdClass(); $o[$obj] = "daten";
echo $o[$obj], " ";
$ao = new ArrayObject(["x" => 1]);
echo count($ao), "\n";
echo implode(",", array_map(fn($c) => $c->name, [new ReflectionClass('ArrayObject')])), " ", PHP_VERSION_ID >= 80000 ? "PHP 8+" : "alt", " ", PHP_OS_FAMILY !== "" ? "os" : "", "\n";21 a1 1 daten 1 ArrayObject PHP 8+ os
Leistung und Betrieb
- OPcache speichert kompilierten Bytecode (in Produktion aktivieren)
- JIT (ab 8.0) bringt vor allem bei rechenintensivem Code etwas
- PHP-FPM + nginx/Apache als Standard-Setup; FrankenPHP, Swoole, RoadRunner halten die Anwendung zwischen Anfragen im Speicher
- Caching (APCu, Redis), Profiling (Xdebug, Blackfire)
Merke
- Union-, Intersection-Typen,
never,readonly, Enums,match - Nullsafe
?->, benannte Argumente, Constructor Promotion, First-class Callables - Attribute für Metadaten, Reflection zum Auslesen
- OPcache und PHP-FPM für den Betrieb
Aufgabe
Baue ein eigenes Attribut #[Pflicht] und eine Funktion, die prüft, ob alle so markierten Eigenschaften gesetzt sind.