Czym jest interfejs w PHP i jak można go zaimplementować?
PHP to popularny język programowania, który jest często używany do tworzenia dynamicznych stron internetowych. Jedną z funkcjonalności PHP jest możliwość tworzenia interfejsów, które umożliwiają zarządzanie metodami, klasami oraz spełniają kluczową funkcję w poliformiźmie. W tym artykule omówimy podstawy tworzenia interfejsu w PHP, a także pokażemy, jak można je wykorzystać w praktyce.
Czym są interfejsy w PHP i do czego służą?
Interfejs w PHP to pewnego rodzaju przepis, który określa, jakie metody i właściwości powinna posiadać dana klasa. W przeciwieństwie do klas, interfejsy nie zawierają implementacji tych metod, ale jedynie ich deklaracje, czyli nazwy, typy argumentów oraz typy wartości zwracanej. Dzięki temu interfejsy służą jako narzędzie do deklarowania wymagań, które muszą być spełnione przez klasy implementujące dany interfejs.
Wszystkie metody zadeklarowane w interfejsie muszą być określone jako publiczne. W interfejsach możemy również definiować stałe. Od PHP w wersji 8.1 stałych nie można nadpisywać w klasach implementujących interfejsy, co wcześniej było możliwe. Dzięki zastosowaniu interfejsów możemy przekazywać i operować na obiektach różnych klas, oczekując, że każda z nich implementuje konkretny zestaw metod a więc możemy ich używać wymiennie gdyż takie obiekty są traktowane jako obiekty tego samego typu. Tę cechę programowania obiektowego nazywamy polimorfizmem.
Jak zaimplementować interfejs w PHP?
Bogatsi o wiedzę z poprzedniego nagłówka możemy przystąpić do wyjaśniania na przykładach.
interface InterfaceName {
public function firstMethodName(): string;
public function secondMethodName(string $foo): bool;
}
class ClassName implements InterfaceName {
public function firstMethodName(): string {
return ‘Hello world’;
}
public function secondMethodName(string $foo): bool {
return $this->thirdMethodName() === $foo;
}
protected function thirdMethodName(): string {
return ‘foo’;
}
}
W przykładzie powyżej zadeklarowaliśmy interfejs InterfaceName, który wymaga od implementujących go klas deklaracji dwóch metod - firstMethodName, zwracającej ciąg znaków, oraz secondMethodName, przyjmującej jeden argument typu string i zwracającej wartość logiczną. Stworzyliśmy również klasę ClassName, implementującą nasz interfejs. Wewnątrz niej musieliśmy stworzyć metody wymagane przez interfejs. Ich modyfikator dostępu, nazwa, kolejność, typ, liczba argumentów oraz typ wartości zwracanej musi zgadzać się z deklaracją wewnątrz interfejsu. W klasach możemy definiować metody, które nie są zadeklarowane w interfejsach.
Dziedziczenie interfejsu w PHP
Interfejsy w PHP mogą być dziedziczone przez inne interfejsy w sposób analogiczny do klas. Pozwala to na bardziej modularne podejście do ich tworzenia, lecz - jak wszystko - powinno to zostać wykorzystane tylko w przypadku, w którym widzimy jasny cel i korzyść takiego podejścia.
Dziedziczenie interfejsów to koncept, którego zastosowanie pozwala na “zaczerpnięcie” przez interfejsy dziedziczące metod i atrybutów zadeklarowanych i zaimplementowanych w interfejsie dziedziczonym. Umożliwia to szerokie możliwości ponownego użycia kodu, zgodnie z zasadą Don’t Repeat Yourself.
Przykład dziedziczenia interfejsów
interface A {
public function foo(): bool;
}
interface B {
public function bar(): bool;
}
interface C extends A, B {
public function baz(): string;
}
class D implements C {
public function foo(): bool {
return true;
}
public function bar(): bool {
return false;
}
public function baz(): string {
return ‘foo’;
}
}
Przykład powyżej przedstawia jedną z najprostszych form dziedziczenia interfejsów. Zadeklarowaliśmy w niej interfejs A oraz B, oba zawierają po jednej metodzie. Oba z nich są rozszerzone w interfejsie C o kolejną metodę. Niżej mamy klasę D, która musi zaimplementować interfejs C. Oznacza to tyle, że klasa D musi zdefiniować metody zadeklarowane w interfejsie A, B oraz C.
Jak dobrze pisać interfejsy w PHP?
Oto kilka wskazówek, których użycie pomoże Ci w pisaniu interfejsów dobrze i czysto.
Nie twórz interfejsów all-in-one
Staraj się ograniczyć liczbę metod i właściwości w interfejsie. Interfejsy powinny być wystarczająco ogólne, aby mogły być implementowane przez różne klasy, ale jednocześnie powinny zawierać tylko te metody i właściwości, które są niezbędne.
Wykorzystaj możliwości języka
Staraj się zawsze definiować typy przyjmowanych i zwracanych wartości. Zmniejszy to ilość potrzebnej dokumentacji, a Twój kod będzie sam tłumaczył swoje działanie.
Skup się na nazewnictwie
Nazwij interfejsy w sposób opisowy i zrozumiały. Nazwy interfejsów powinny być zwięzłe, ale jednocześnie dokładnie opisywać ich przeznaczenie i zawartość. Unikaj również implementowania wielu interfejsów, które zawierają metody o tych samych nazwach - może to prowadzić do komplikacji kodu.
Nie komplikuj
Używaj interfejsów tylko wtedy, gdy jest to potrzebne. Nie każda klasa musi implementować interfejs - w niektórych przypadkach lepszym rozwiązaniem może być na przykład dziedziczenie z innej klasy.
Dokumentacja jest kluczowa
Dokumentuj interfejsy tak samo, jak inne elementy kodu. Interfejsy powinny być dokumentowane w sposób czytelny, zwięzły i zrozumiały. Inni programiści powinni być w stanie łatwo zobaczyć, jakie metody i właściwości są dostępne, jaki jest ich cel i przeznaczenie oraz kiedy można je wykorzystać.
Stosowanie tych dobrych praktyk pomoże Ci tworzyć bardziej elastyczne i czytelne interfejsy w PHP.
Przykłady
Poniżej znajdują się przykłady interfejsów, które stosują wybrane z wyżej wymienionych dobrych praktyk.
Nie twórz interfejsów all-in-one
Dobrym przykładem interfejsu o zbyt szerokiej definicji będzie interfejs koszyka, który powinien zawierać wyłącznie niezbędne metody publiczne od dodawania, usuwania oraz otrzymywania elementów z koszyka. Interfejs ten nie powinien zawierać dodatkowych deklaracji metod od na przykład płatności, kalkulowania kosztu dostawy itp. Te funkcjonalności powinny mieć zarówno odrębny interfejs, jak i klasy.
Nazwij interfejsy w sposób opisowy i zrozumiały:
Nazwa interfejsu powinna jasno definiować jego cel, być generyczna, lecz z drugiej strony na tyle konkretna, aby po samym jej przeczytaniu programista wiedział, do czego służy.
// Dobry przykład
interface UserRepositoryInterface {
// Metody obsługujące użytkowników w bazie danych
}
// Zły przykład
interface Repo {
// Metody obsługujące użytkowników w bazie danych
}
Kiedy stosować interfejsy w PHP?
Jak już wiesz, interfejs to koncept pozwalający na upewnienie się, że dana klasa zawiera konkretne metody i właściwości. W PHP - tak jak i w każdym obiektowym języku programowania - najlepiej jest używać interfejsów wtedy, gdy chcemy upewnić się, że klasa spełnia określony zbiór kryteriów lub wytycznych. Dla przykładu, jeśli chcesz upewnić się, że wiele klas implementuje te same metody i nie chcesz używać dziedziczenia, możesz użyć interfejsu, żeby zdefiniować te metody i mieć później pewność, że są one zaimplementowane w każdej z klas, które ten interfejs implementują. Dodatkowo używając interfejsów, tworzysz kod modularny, który jest łatwiejszy w utrzymaniu i rozwoju.
Interfejs PHP - podsumowanie
Interfejsy to ważny koncept w programowaniu obiektowym, gdyż możliwość zdefiniowania listy metod, które musi posiadać dana klasa pozwala na pewnego rodzaju elastyczność i zwiększa możliwości ponownego użycia kodu. Główną korzyścią jest jednak możliwość tworzenia kodu poliformicznego. Podczas tworzenia systemu używając OOP (object-oriented programming) ważnym jest by rozważnie korzystać z obu tych konceptów - interfejsów i polimorfizmu by nie komplikować kodu w miejsach, które tego nie wymagają a wyłącznie w takich, w których przynoszą one jasno widoczne korzyści.
Dołącz do naszego zespołu, gdzie dzielimy się wiedzą i poruszamy techniczne tematy na naszych kanałach na Slacku, a także podczas wewnętrznych szkoleń!