SmartObject
SmartObject przez lata usprawniał zachowanie obiektów w PHP. Od wersji PHP 8.4 wszystkie jego funkcje są już częścią samego PHP, tym samym kończąc swoją historyczną misję jako pionier nowoczesnego podejścia obiektowego w PHP.
Instalacja:
SmartObject powstał w 2007 roku jako rewolucyjne rozwiązanie niedoskonałości ówczesnego modelu obiektowego PHP. W czasie, gdy PHP borykało się z wieloma problemami w projektowaniu obiektowym, wprowadził znaczące usprawnienia i uproszczenia w pracy programistów. Stał się legendarną częścią frameworka Nette. Oferował funkcjonalności, które PHP zyskało dopiero wiele lat później – od walidacji dostępu do właściwości obiektów po zaawansowaną obsługę błędów. Wraz z nadejściem PHP 8.4 zakończył swoją historyczną misję, ponieważ wszystkie jego funkcje stały się natywną częścią języka. Wyprzedził rozwój PHP o imponujące 17 lat.
SmartObject przeszedł ciekawą ewolucję techniczną. Początkowo był zaimplementowany jako klasa Nette\Object
,
po której inne klasy dziedziczyły potrzebną funkcjonalność. Znacząca zmiana nastąpiła wraz z PHP 5.4, które wprowadziło
obsługę trait. Umożliwiło to transformację w trait Nette\SmartObject
, co przyniosło większą
elastyczność – programiści mogli wykorzystywać funkcjonalność nawet w klasach, które już dziedziczyły po innej klasie.
Podczas gdy oryginalna klasa Nette\Object
przestała istnieć wraz z PHP 7.2 (które zabroniło nazywania klas
słowem ‚Object‘), trait Nette\SmartObject
żyje nadal.
Przyjrzyjmy się funkcjom, które kiedyś oferował Nette\Object
, a później Nette\SmartObject
.
Każda z tych funkcji stanowiła w swoim czasie znaczący krok naprzód w programowaniu obiektowym w PHP.
Spójne stany błędów
Jednym z najbardziej palących problemów wczesnego PHP było niespójne zachowanie podczas pracy z obiektami.
Nette\Object
wprowadził porządek i przewidywalność do tego chaosu. Zobaczmy, jak wyglądało oryginalne
zachowanie PHP:
Fatal error powodował zakończenie aplikacji bez możliwości reakcji. Ciche zapisywanie do nieistniejących członków bez
ostrzeżenia mogło prowadzić do poważnych błędów, które trudno było wykryć. Nette\Object
przechwytywał
wszystkie te przypadki i rzucał wyjątek MemberAccessException
, co pozwalało programistom reagować na błędy
i je obsługiwać:
Od PHP 7.0 język nie powoduje już nieprzechwytywanych błędów krytycznych, a od PHP 8.2 dostęp do niezadeklarowanych członków jest traktowany jako błąd.
Podpowiedź „Did you mean?“
Nette\Object
wprowadził bardzo przydatną funkcję: inteligentne podpowiedzi przy literówkach. Gdy programista
popełnił błąd w nazwie metody lub zmiennej, nie tylko zgłaszał błąd, ale także oferował pomoc w postaci sugestii
prawidłowej nazwy. Ta charakterystyczna wiadomość, znana jako „did you mean?“, zaoszczędziła programistom godziny
szukania literówek:
Dzisiejsze PHP nie ma wprawdzie żadnej formy „did you mean?", ale ten dodatek potrafi uzupełniać Tracy. A nawet automatycznie poprawiać takie błędy.
Properties z kontrolowanym dostępem
Znaczącą innowacją, którą SmartObject wprowadził do PHP, były properties z kontrolowanym dostępem. Ta koncepcja, powszechna w językach takich jak C# czy Python, pozwoliła programistom elegancko kontrolować dostęp do danych obiektu i zapewnić ich spójność. Properties są potężnym narzędziem programowania obiektowego. Działają jak zmienne, ale w rzeczywistości są reprezentowane przez metody (gettery i settery). Umożliwia to walidację danych wejściowych lub generowanie wartości w momencie odczytu.
Aby używać properties, musisz:
- Dodać do klasy adnotację w formacie
@property <type> $xyz
- Utworzyć getter o nazwie
getXyz()
lubisXyz()
, setter o nazwiesetXyz()
- Zapewnić, aby getter i setter były public lub protected. Są opcjonalne – mogą więc istnieć jako read-only lub write-only property
Zobaczmy praktyczny przykład na klasie Circle, gdzie użyjemy properties, aby zapewnić, że promień będzie zawsze
nieujemny. Zastąpimy oryginalne public $radius
przez property:
Od PHP 8.4 można osiągnąć tę samą funkcjonalność za pomocą property hooks, które oferują znacznie elegantszą i zwięzłą składnię:
Extension methods
Nette\Object
wprowadził do PHP kolejną interesującą koncepcję zainspirowaną nowoczesnymi językami
programowania – extension methods. Ta funkcja, zapożyczona z C#, pozwoliła programistom elegancko rozszerzać istniejące
klasy o nowe metody bez konieczności ich modyfikacji lub dziedziczenia. Na przykład można było dodać do formularza metodę
addDateTime()
, która dodaje własny DateTimePicker:
Extension methods okazały się niepraktyczne, ponieważ ich nazwy nie były podpowiadane przez edytory, przeciwnie – zgłaszały, że metoda nie istnieje. Dlatego ich wsparcie zostało zakończone. Obecnie częściej stosuje się kompozycję lub dziedziczenie do rozszerzania funkcjonalności klas.
Pobieranie nazwy klasy
Do pobrania nazwy klasy SmartObject oferował prostą metodę:
Dostęp do reflection i adnotacji
Nette\Object
oferował dostęp do reflection i adnotacji za pomocą metod getReflection()
i
getAnnotation()
. To podejście znacząco uprościło pracę z metainformacjami klas:
Od PHP 8.0 można uzyskiwać dostęp do metainformacji za pomocą atrybutów, które oferują jeszcze większe możliwości i lepszą kontrolę typów:
Method gettery
Nette\Object
oferował elegancki sposób przekazywania metod, jakby były zmiennymi:
Od PHP 8.1 można wykorzystać tzw. first-class callable syntax, która rozwija ten koncept jeszcze dalej:
Wydarzenia
SmartObject oferuje uproszczoną składnię do pracy z wydarzeniami. Wydarzenia pozwalają obiektom informować inne części aplikacji o zmianach swojego stanu:
Kod $this->onChange($this, $radius)
jest równoważny następującej pętli:
Ze względu na przejrzystość zalecamy unikanie magicznej metody $this->onChange()
. Praktycznym zamiennikiem
jest funkcja Nette\Utils\Arrays::invoke: