Erkunde das Innenleben von Attributen, readonly, First-Class-Callables und der strengen Typisierung von PHP 8.
Diese Lektion in Kodokon öffnenAttribute ersetzen die Docblock-Annotationen durch echte Klassen, die von der Engine validiert werden. Ein Attribut ist nichts als schlafende Metadaten: #[Route('/users')] zu schreiben erzeugt kein Objekt. Es erwacht erst zum Leben, wenn Code es per Reflection abfragt und newInstance() aufruft - genau das tun Frameworks beim Start, um ihre Routing-Tabellen aufzubauen. Das erlaubte Ziel (TARGET_METHOD, TARGET_CLASS...) wird selbst durch ein Attribut auf der Attributklasse deklariert.
<?php
declare(strict_types=1);
#[Attribute(Attribute::TARGET_METHOD)]
final class Route
{
public function __construct(
public readonly string $path,
public readonly string $method = 'GET'
) {}
}
final class UserController
{
#[Route('/users', method: 'GET')]
public function index(): array
{
return ['users' => []];
}
}
$ref = new ReflectionMethod(
UserController::class,
'index'
);
foreach ($ref->getAttributes(Route::class) as $attr) {
$route = $attr->newInstance();
echo $route->method, ' ', $route->path, PHP_EOL;
}readonly - Eigenschaften in 8.1, ganze Klassen in 8.2 - garantiert, dass eine Eigenschaft nur einmal geschrieben wird, und zwar aus dem Geltungsbereich der Klasse heraus. Es ist das Werkzeug für Value Objects: Jede "Änderung" wird zur Konstruktion eines neuen Objekts, was eine ganze Familie von Bugs mit geteiltem Zustand ausschließt. Eine readonly-Klasse verlangt, dass alle ihre Eigenschaften typisiert und nicht statisch sind.
<?php
declare(strict_types=1);
final readonly class Money
{
public function __construct(
public int $amount,
public string $currency
) {}
public function add(Money $other): self
{
if ($other->currency !== $this->currency) {
throw new InvalidArgumentException(
'Currency mismatch'
);
}
return new self(
$this->amount + $other->amount,
$this->currency
);
}
}
$total = new Money(500, 'EUR');
$total = $total->add(new Money(250, 'EUR'));
echo $total->amount;Die First-Class-Callable-Syntax strtoupper(...) (PHP 8.1) erzeugt aus jeder Funktion oder Methode eine Closure. Anders als Zeichenketten wie 'strtoupper' oder Arrays wie [$obj, 'method'] wird das Symbol schon bei der Erzeugung überprüft, und die Werkzeuge der statischen Analyse verfolgen die Typen durchgehend. Bei einer Instanzmethode fängt die Closure das Objekt ein, bei einer statischen Methode nur die Klasse.
<?php
declare(strict_types=1);
$words = ['php', 'rust', 'go'];
$upper = strtoupper(...);
var_dump($upper('php'));
print_r(array_map(strtoupper(...), $words));
final class Mailer
{
public function send(string $to): bool
{
return $to !== '';
}
public static function ping(): string
{
return 'pong';
}
}
$mailer = new Mailer();
$send = $mailer->send(...);
$ping = Mailer::ping(...);
var_dump($send('dev@example.org'), $ping());