Slovník pojmů
Konstruktor
Konstruktor vytváří objekt v platném výchozím stavu. Není jen mechanickým přiřazením hodnot: nastavuje invarianty a přijímá povinné závislosti, aby objekt šel bezpečně použít.
Stručná definice
Platná instance od okamžiku vytvoření.
Konstruktor patří třídě a objektu a běží při vytvoření nové instance. Může ověřit povinné ID, zákazníka nebo měnu a odmítnout stav, ve kterém by objekt neměl existovat. Výjimka dává smysl tam, kde vstup porušuje invariant, nikoli jako náhrada běžného větvení.
Předání nutné služby přes konstruktor je constructor injection, konkrétní forma dependency injection. PHP property promotion zkracuje zápis vlastnosti a parametru, ale nemění návrhový princip.
Jaký problém řeší
Zajišťuje, že objekt nevznikne napůl hotový.
Konstruktor sdružuje data a závislosti, bez nichž veřejné metody nemohou dodržet svůj kontrakt.
- povinné ID, zákazník a měna objednávky
- předání závislosti na úložišti, hodinách nebo gateway
- ověření invariantů při vzniku hodnotového objektu
- nastavení výchozího platného stavu
Praktický příklad
Objednávka vyžaduje tři povinné hodnoty
Objednávka bez identifikátoru, zákazníka nebo měny by byla neúplná instance. Konstruktor proto nepovolí prázdné hodnoty. V reálném projektu mohou být tyto hodnoty vlastními typy místo stringů.
V konstruktoru běžně nedělejte pomalé síťové nebo databázové I/O. Taková práce komplikuje vytvoření objektu, testování a obsluhu selhání; patří obvykle do služby nebo factory.
PHP
final class Order
{
public function __construct(
private readonly string $id,
private readonly string $customerId,
private readonly string $currency,
) {
if ($id === '' || $customerId === '' || $currency === '') {
throw new InvalidArgumentException('Objednávka vyžaduje ID, zákazníka a měnu.');
}
}
}
Jak funguje
Od vstupů k platné instanci
Diagram ukazuje, proč konstruktor není jen pohodlné místo pro přiřazení vlastností.
- Vstupy a závislosti Volající dodá vše, bez čeho objekt nemůže fungovat.
- Ověření Konstruktor odmítne porušení invariantů.
- Inicializace Uloží platný počáteční stav.
- Instance Veřejné metody pracují s objektem, který již splňuje svůj kontrakt.
Hlavní části a varianty
Vytvoření objektu má několik zodpovědností.
Rozsah konstruktoru má zůstat malý a předvídatelný.
Povinné parametry
Vyjadřují nezbytná data nebo spolupracovníky; nullable parametr nemá jen obcházet povinnost hodnoty.
Constructor injection
Závislost vzniká mimo objekt a konstruktor ji přijme; objekt ji proto nemusí potají vytvářet.
Factory
Factory může nabídnout pojmenované alternativní způsoby vzniku, převod vstupu nebo složitější přípravu.
Rodičovský konstruktor
V PHP ho potomek s vlastním konstruktorem nevolá automaticky; pokud je potřebný, volá se parent::__construct().
Omezení a časté chyby
Příliš pohodlný konstruktor může skrýt špatný návrh.
Co pomáhá
- udržet objekt po konstrukci v platném stavu
- předávat povinné závislosti explicitně
- používat factory, pokud vznik vyžaduje pojmenovanou přípravu
Rizika
- databázový nebo síťový dotaz při každém vytvoření objektu
- příliš mnoho parametrů jako signál mnoha odpovědností
- nullable hodnoty jen pro snadnější zavolání
- nevolání nezbytného rodičovského konstruktoru
Praktické použití
Vytvoření má být rychlé, čitelné a platné.
Když konstruktor potřebuje mnoho parametrů, nejde automaticky o chybu, ale je vhodné prověřit, zda objekt nespojuje několik odpovědností. Pomoci může hodnotový objekt nebo změna hranice služby.
Constructor injection usnadňuje testování, protože test dodá jednoduchou závislost předem. Samotné předání přes konstruktor však nezaručuje vhodný kontrakt ani malou odpovědnost třídy.
Konstruktor se liší od běžné metody tím, že nastavuje okamžik vzniku platné instance. Factory naopak může připravit složitější vstup nebo pojmenovat více způsobů vzniku. Oba přístupy se mohou doplňovat: factory sestaví data a konstruktor stále chrání invarianty. Dependency injection je širší způsob předání závislosti; constructor injection je jen jeho konkrétní forma.
Výjimka z konstruktoru dává smysl, pokud by pokračování vytvořilo objekt s porušeným invariantem. Pro očekávané chyby formuláře je však často vhodnější vrátit výsledek validace dřív, než se objekt začne vytvářet. Při návrhu je důležité rozlišit neplatný stav doménového objektu od neúplných dat, která uživatel teprve vyplňuje.
Povinné závislosti by proto měly být viditelné v signatuře. Volitelná závislost má mít skutečně smysluplné výchozí chování; nullable parametr není obecný prostředek, jak obejít rozhodnutí o návrhu. Když se konstruktor natahuje o technické větve a přípravu vstupu, je obvykle lepší přenést tuto práci na factory nebo aplikační službu.
Konstruktor má mít také srozumitelnou cenu provedení. Vytvoření několika hodnotových objektů by nemělo neočekávaně otevírat síťové spojení nebo načítat další data z databáze. Pokud objekt potřebuje data vyhledat, je obvykle čitelnější provést tuto práci předem v aplikační službě a do konstruktoru předat již připravený vstup. Test pak ověřuje invariantu bez závislosti na infrastruktuře.
Kontrola změny
Zkontrolujte, co objekt slibuje od prvního okamžiku.
Konstruktor má být místem pro invariantu, nikoli skrytým workflow s I/O.
- popsat povinné parametry a jejich význam
- odmítnout neplatný počáteční stav
- neprovádět běžné pomalé I/O
- zkontrolovat počet a soudržnost závislostí
Časté otázky
Konstruktory v praxi
Je konstruktor jen přiřazení vlastností?
Ne. Má zajistit platný počáteční stav a může vyžadovat povinné závislosti.
Kdy zvolit factory?
Když vznik objektu má více pojmenovaných variant nebo vyžaduje přípravu vstupu.
Proč nedělat databázový dotaz v konstruktoru?
Zpomaluje a znepředvídatelňuje vytvoření objektu a komplikuje testy i chyby.
Je constructor injection totéž co DI?
Je to konkrétní podoba dependency injection, nikoli celý koncept.
Osobní zkušenost
Platný stav objektu šetří kontroly v celém zbytku aplikace.
V PHP a architektonickém návrhu používám konstruktory pro jasné invarianty a explicitní závislosti.