SmartObject
SmartObject po léta vylepšoval chování objektů v PHP. Od verze PHP 8.4 jsou již všechny jeho funkce součástí samotného PHP, čímž završil svou historickou misi být průkopníkem moderního objektového přístupu v PHP.
Instalace:
SmartObject vznikl v roce 2007 jako revoluční řešení nedostatků tehdejšího objektového modelu PHP. V době, kdy PHP trpělo řadou problémů s objektovým návrhem, přinesl výrazné vylepšení a zjednodušení práce pro vývojáře. Stal se legendární součástí frameworku Nette. Nabízel funkcionalitu, kterou PHP získalo až o mnoho let později – od kontrolu přístupu k vlastnostem objektů až po sofistikované syntaktické cukrátka. S příchodem PHP 8.4 završil svou historickou misi, protože všechny jeho funkce se staly nativní součástí jazyka. Předběhl vývoj PHP o pozoruhodných 17 let.
Technicky prošel SmartObject zajímavým vývojem. Původně byl implementován jako třída Nette\Object
, od
které ostatní třídy dědily potřebnou funkcionalitu. Zásadní změna přišla s PHP 5.4, které přineslo podporu trait. To
umožnilo transformaci do podoby traity Nette\SmartObject
, což přineslo větší flexibilitu – vývojáři mohli
funkcionalitu využít i ve třídách, které již dědily od jiné třídy. Zatímco původní třída
Nette\Object
zanikla s příchodem PHP 7.2 (které zakázalo pojmenování tříd slovem Object
),
traita Nette\SmartObject
žije dál.
Pojďme si projít vlastnosti, které kdysi Nette\Object
a později Nette\SmartObject
nabízeli.
Každá z těchto funkcí ve své době představovala významný krok vpřed v oblasti objektově orientovaného programování
v PHP.
Konzistentní chybové stavy
Jedním z nejpalčivějších problémů raného PHP bylo nekonzistentní chování při práci s objekty.
Nette\Object
přinesl do tohoto chaosu řád a předvídatelnost. Podívejme se, jak vypadalo původní
chování PHP:
Fatal error ukončil aplikaci bez možnosti jakkoliv reagovat. Tichý zápis do neexistujících členů bez upozornění mohl
vést k závažným chybám, které šly obtížné odhalit. Nette\Object
všechny tyto případy zachytával a
vyhazoval výjimku MemberAccessException
, což umožnilo programátorům na chyby reagovat a řešit je.
Od PHP 7.0 již jazyk nezpůsobuje nezachytitelné fatal error a od PHP 8.2 je přístup k nedeklarovaným členům považován za chybu.
Nápověda „Did you mean?“
Nette\Object
přišel s velmi příjemnou funkcí: inteligentní nápovědou při překlepech. Když vývojář
udělal chybu v názvu metody nebo proměnné, nejen oznámil chybu, ale také nabídl pomocnou ruku v podobě návrhu
správného názvu. Tato ikonická hláška, známá jako „did you mean?“, ušetřila programátorům hodiny hledání
překlepů:
Dnešní PHP sice nemá žádnou podobu „did you mean?“, ale tento dovětek umí do chyb doplňovat Tracy. A dokonce takové chyby i samo opravovat.
Properties s kontrolovaným přístupem
Významnou inovací, kterou SmartObject přinesl do PHP, byly properties s kontrolovaným přístupem. Tento koncept, běžný v jazycích jako C# nebo Python, umožnil vývojářům elegantně kontrolovat přístup k datům objektu a zajistit jejich konzistenci. Properties jsou mocným nástrojem objektově orientovaného programování. Fungují jako proměnné, ale ve skutečnosti jsou reprezentovány metodami (gettery a settery). To umožňuje validovat vstupy nebo generovat hodnoty až v momentě čtení.
Pro používání properties musíte:
- Přidat třídě anotaci ve tvaru
@property <type> $xyz
- Vytvořit getter s názvem
getXyz()
neboisXyz()
, setter s názvemsetXyz()
- Zajistit, aby getter a setter byly public nebo protected. Jsou volitelné – mohou tedy existovat jako read-only nebo write-only property
Ukažme si praktický příklad na třídě Circle, kde properties využijeme k zajištění, že poloměr bude vždy
nezáporné číslo. Nahradíme původní public $radius
za property:
Od PHP 8.4 lze dosáhnout stejné funkcionality pomocí property hooks, které nabízí mnohem elegantnější a stručnější syntaxi:
Extension methods
Nette\Object
přinesl do PHP další zajímavý koncept inspirovaný moderními programovacími jazyky –
extension methods. Tato funkce, převzatá z C#, umožnila vývojářům elegantně rozšiřovat existující třídy o nové
metody bez nutnosti je upravovat nebo od nich dědit. Třeba jste si mohli do formuláře přidat metodu
addDateTime()
, která přidá vlastní DateTimePicker:
Extension metody se ukázaly jako nepraktické, protože jejich názvy nenapovídaly editory, naopak hlásily, že metoda neexistuje. Proto byla jejich podpora ukončena. Dnes je běžnější využívat kompozici nebo dědičnost pro rozšíření funkcionality tříd.
Zjištění názvu třídy
Pro zjištění názvu třídy nabízel SmartObject jednoduchou metodu:
Přístup k reflexi a anotacím
Nette\Object
nabízel přístup k reflexi a anotacím pomocí metod getReflection()
a
getAnnotation()
. Tento přístup významně zjednodušil práci s metainformacemi tříd:
Od PHP 8.0 je možné přistupovat k metainformacím v podobě atributů, které nabízí ještě větší možnosti a lepší typovou kontrolu:
Method gettery
Nette\Object
nabízel elegantní způsob, jak předávat metody jako kdyby šlo o proměnné:
Od PHP 8.1 je možné využít tzv. first-class callable syntax, která tento koncept posouvá ještě dál:
Události
SmartObject nabízí zjednodušenou syntax pro práci s událostmi. Události umožňují objektům informovat ostatní části aplikace o změnách svého stavu:
Kód $this->onChange($this, $radius)
je ekvivalentní následujícímu cyklu:
Kvůli srozumitelnosti doporučujeme se magické metodě $this->onChange()
vyhnout. Praktickou náhradou je
třeba funkce Nette\Utils\Arrays::invoke: