Fáze požadavku: 7. Doménová vrstva & DTO
Modul 1 · Lekce 2

Readonly třídy, DTO objekty a Constructor Property Promotion

💡 Shrnutí lekce

Poznejte sílu neměnných datových struktur (DTO), zjednodušení kódu pomocí Constructor Property Promotion a důvody, proč je immutabilita klíčová v moderním FrankenPHP prostředí.

Revoluce v psaní tříd: Constructor Property Promotion

Před verzí PHP 8.0 vyžadovala definice jednoduchého datového objektu (DTO) značné množství duplicitního boilerplate kódu:

// Zastaralý přístup v PHP 7:
class OldUserDto {
    private string $name;
    private string $email;

    public function __construct(string $name, string $email) {
        $this->name = $name;
        $this->email = $email;
    }
    public function getName(): string { return $this->name; }
    public function getEmail(): string { return $this->email; }
}

V PHP 8.0 přišla zásadní inovace: Constructor Property Promotion. Pokud před parametr v konstruktoru přidáte modifikátor viditelnosti (public, protected nebo private), PHP engine automaticky:

  1. Deklaruje vlastnost třídy se stejným jménem a typem.
  2. Při vytvoření instance přiřadí předaný argument přímo do této vlastnosti.

Konstruktor se tak zredukuje na pouhou signaturu bez jediného řádku v těle!


Neměnnost s readonly class

V PHP 8.1 byly představeny readonly vlastnosti – vlastnost lze nastavit pouze jednou (typicky v konstruktoru) a jakýkoliv další pokus o zápis vyvolá Error.

PHP 8.2 posunulo koncept ještě dál představením readonly class:

final readonly class AnatomyFileNodeData
{
    public function __construct(
        public string $path,
        public string $category,
        public string $description,
        public bool $exists,
        public int $lineCount,
        public int $sizeBytes,
        public string $content,
    ) {}
}

Když označíte celou třídu klíčovým slovem readonly:

  • Všechny vlastnosti třídy se automaticky stanou readonly (nemusíte psát readonly před každou proměnnou).
  • Třídě nelze dynamicky přidávat vlastnosti za běhu ($node->foo = 'bar' způsobí chybu).
  • Zaručuje absolutní immutabilitu (neměnnost) stavu objektu po jeho inicializaci.

Proč je immutabilita kritická ve FrankenPHP a moderních runtimech?

V klasickém PHP-FPM modelu proces po dokončení každého HTTP požadavku zemře a veškerá paměť je uvolněna.

V moderních aplikačních serverech jako je FrankenPHP (nebo RoadRunner) však PHP běží v tzv. Worker módu. Aplikační proces žije nepřetržitě v paměti a postupně odbavuje tisíce HTTP požadavků za sebou:

  1. Pokud by vaše služby nebo DTO objekty měly modifikovatelný vnitřní stav (mutable state), mohlo by dojít k prosáknutí dat mezi dvěma různými uživateli!
  2. Neměnné DTO objekty (readonly) garantují, že jakmile data jednou vytvoříte, žádná jiná část aplikace je nemůže nepozorovaně přepsat.
  3. Kód je plně bezpečný, predikovatelný a vláknově stabilní.

V naší aplikaci agy-laravel používáme final readonly class pro všechny datové přenosy mezi službou AnatomyInspectorService, Livewire komponentami a Blade šablonami.

💻 Klíčová konstrukce z praxe
<?php

declare(strict_types=1);

namespace App\Data;

// Ukázka reálné neměnné třídy z naší aplikace (app/Data/AnatomyFileNodeData.php)
final readonly class AnatomyFileNodeData
{
    public function __construct(
        public string $path,        // Relativní cesta k souboru v projektu
        public string $category,    // Architektonická vrstva (např. "Controller", "Service")
        public string $description, // Popis role souboru v architektuře
        public bool $exists,        // Zda soubor fyzicky existuje na disku
        public int $lineCount,      // Počet řádků kódu
        public int $sizeBytes,      // Velikost souboru v bajtech
        public string $content,     // Bezpečně načtený obsah pro syntax highlighting
    ) {}
}

🎯 Ověření znalostí z lekce

Kvíz otestuje pochopení architektury a reálného kódu probíraného v této lekci.

Otázka 1 z 3

Jaký je hlavní přínos označení třídy jako readonly class v PHP 8.2+?

Otázka 2 z 3

Jak funguje Constructor Property Promotion zavedené v PHP 8.0?

Otázka 3 z 3

Proč je používání neměnných DTO (immutable objects) obzvlášť důležité ve FrankenPHP worker režimu?

Zodpovězeno: 0 / 3
🔬 Živá anatomie v této aplikaci
2 soubory
Na co se v kódu zaměřit: V souboru app/Data/AnatomyFileNodeData.php prozkoumej definici neměnného uzlu souborového stromu. Všimni si kombinace final readonly class a Constructor Property Promotion. Objekt je kompletně definován na pouhých 18 řádcích kódu bez jediného getteru či setteru!
cesta: app/Data/AnatomyFileNodeData.php
18 řádků · 0.4 KB
Neměnné PHP 8.4 readonly DTO reprezentující analyzovaný soubor anatomie aplikace (řádky, bajty, obsah, popis).
1 <?php
2
3 declare(strict_types=1);
4
5 namespace App\Data;
6
7 final readonly class AnatomyFileNodeData
8 {
9 public function __construct(
10 public string $path,
11 public string $category,
12 public string $description,
13 public bool $exists,
14 public int $lineCount,
15 public int $sizeBytes,
16 public string $content,
17 ) {}
18 }
19
cesta: app/Data/LessonContentData.php
25 řádků · 0.5 KB
Readonly DTO s kompletními daty lekce pro bezpečné předávání mezi modely, controllery a šablonami.
1 <?php
2
3 declare(strict_types=1);
4
5 namespace App\Data;
6
7 use App\Enums\LifecyclePhase;
8
9 final readonly class LessonContentData
10 {
11 /**
12 * @param list<string> $anatomyFiles
13 */
14 public function __construct(
15 public string $moduleSlug,
16 public string $lessonSlug,
17 public string $title,
18 public string $summary,
19 public string $renderedHtml,
20 public ?string $codeSnippet,
21 public array $anatomyFiles,
22 public ?string $anatomyNote,
23 public LifecyclePhase $lifecyclePhase,
24 ) {}
25 }
26
Zdroj: skutečné soubory této aplikace Plný průzkumník anatomie →