Striktní typy (strict_types=1) a moderní typový systém
Pochopte, jak direktiva declare(strict_types=1) chrání kód před tichými chybami z implicitní konverze typů a jak typový systém v PHP 8.4 garantuje spolehlivost doménové logiky.
Co je striktní typování a proč je v moderním PHP klíčové
Historicky bylo PHP známé svou extrémně benevolentní typovou konverzí (type coercion). Pokud funkce očekávala celé číslo int a vy jste jí předali řetězec "42" nebo boolean true, PHP hodnotu tiše přetypovalo bez jakéhokoliv varování. V enterprise aplikacích a komplexních systémech však toto chování vede k tichým chybám, které se často projeví až v produkci v podobě nekonzistentních dat.
Od PHP 7.0 máme k dispozici direktivu:
declare(strict_types=1);
Umístěním této direktivy na úplně první řádek souboru (hned za otevírací značku <?php) dáváte PHP enginu instrukci: „Při volání jakýchkoliv funkcí a metod v tomto souboru striktně vyžaduj shodu deklarovaných a předaných typů. Žádné automatické přetypování řetězců na čísla nebo null na prázdný řetězec není dovoleno.“
Pokud dojde k předání nekompatibilního typu, PHP okamžitě vyhodí fatální výjimku TypeError. Chyba je tak odhalena okamžitě během vývoje nebo při běhu automatizovaných testů.
Evoluce typového systému až k PHP 8.4
Typový systém moderního PHP patří k nejpropracovanějším mezi dynamickými jazyky. Podívejme se na klíčové milníky:
- PHP 7.0–7.4: Skalární typy (
int,float,string,bool), návratové typy, nullable typy (?string),voida typované vlastnosti tříd (public string $name). - PHP 8.0: Union types (
int|float), typmixeda návratový typneverpro funkce, které vždy vyhazují výjimku nebo ukončují běh (exit). - PHP 8.1: Intersection types (
Countable&Traversable), návratový typnevera podporafinal class constants. - PHP 8.2: DNF typy (Disjunctive Normal Form) – kombinace Union a Intersection typů, např.
(HasTitle&HasSlug)|null. - PHP 8.4: Asymetrická viditelnost (asymmetric visibility), nové funkce pro práci s poli (
array_find,array_any) a ještě striktnější kontroly zanořených typů.
Rozsah platnosti (Scope) direktivy strict_types
Zásadní vlastností direktivy declare(strict_types=1); je, že funguje per-file (souborově):
- Ovlivňuje volání, která se provádějí v souboru se zapnutým striktním režimem.
- Pokud soubor
A.phpmástrict_types=1a zavolá metodu třídy definované vB.php, parametry jsou striktně ověřeny. - Pokud soubor
C.phpnemástrict_types=1a zavolá stejnou metodu, PHP použije slabé typování pro argumenty tohoto volání.
Proto v našem projektu agy-laravel uplatňujeme nekompromisní architektonické pravidlo definované v AGENTS.md: Každý PHP soubor v app/, config/, database/, routes/ a tests/ musí začínat deklarací declare(strict_types=1);.
Praktický dopad na doménové objekty v agy-laravel
V souboru app/Data/LessonContentData.php využíváme striktní typy v konstruktoru DTO:
public function __construct(
public string $moduleSlug,
public string $lessonSlug,
public string $title,
public string $summary,
public string $renderedHtml,
public ?string $codeSnippet,
public array $anatomyFiles,
public ?string $anatomyNote,
public LifecyclePhase $lifecyclePhase,
) {}
Všimněte si:
?string $codeSnippet: Otazník explicitně vyjadřuje, že hodnota může býtstringnebonull. Pokud by tam otazník nebyl a předali jsmenull, PHP okamžitě vyvoláTypeError.LifecyclePhase $lifecyclePhase: Argument musí být instancí konkrétního enumu, nikoliv libovolný string.
<?php
declare(strict_types=1);
namespace App\Data;
use App\Enums\LifecyclePhase;
// Ukázka striktně typovaného DTO z naší aplikace (app/Data/LessonContentData.php)
final readonly class LessonContentData
{
/**
* @param list<string> $anatomyFiles
*/
public function __construct(
public string $moduleSlug,
public string $lessonSlug,
public string $title,
public string $summary,
public string $renderedHtml,
public ?string $codeSnippet, // Nullable skalární typ: string nebo null
public array $anatomyFiles, // Pole cest k souborům
public ?string $anatomyNote, // Průvodce anatomií pro studenta
public LifecyclePhase $lifecyclePhase, // Nativní PHP 8.1+ Enum
) {}
}
🎯 Ověření znalostí z lekce
Kvíz otestuje pochopení architektury a reálného kódu probíraného v této lekci.
Co přesně způsobí uvedení direktivy declare(strict_types=1); na začátku PHP souboru?
Jaký je rozsah platnosti (scope) direktivy declare(strict_types=1);?
Co v moderním PHP vyjadřuje typový zápis ?string $codeSnippet?
| 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 | |