PHP/Interfejsy: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Nie podano opisu zmian
Nie podano opisu zmian
 
Linia 4:
Dziedziczenie jest jednym z najważniejszych mechanizmów programowania obiektowego, gdyż pozwala rozszerzać istniejące klasy oraz traktować je bardziej ogólnie. Podobnie jak większość języków programowania, PHP nie zezwala jednak na tzw. ''dziedziczenie wielokrotne'', czyli możliwość rozszerzenia więcej niż jednej klasy naraz:
 
<sourcesyntaxhighlight lang="php" line highlight="2"><?php
class MultipleInheritance extends FirstClass, SecondClass
{
 
} // end MultipleInheritance;
</syntaxhighlight>
</source>
 
Przy tradycyjnej konstrukcji systemu obiektowego w języku dziedziczenie wielokrotne wprowadza wiele patologii, a jego poprawne używanie wymaga od programisty ścisłej dyscypliny i szczegółowej wiedzy o hierarchii klas. Zamiast niego, PHP wykorzystuje zaczerpniętą z Javy ideę interfejsów.
Linia 22:
Rozpatrzmy prosty system uprawnień. Główna klasa stanowi interfejs dostępu, który potrafi odpowiadać na pytania, czy użytkownik powinien mieć dostęp do wskazanego zasobu. Oprócz tego chcemy mieć zestaw innych klas, które potrafiłyby generować listę uprawnień dla naszego systemu. Nie chcemy ograniczać możliwości ich dziedziczenia, dlatego zamiast tego utworzymy interfejs opisujący, czego system uprawnień wymaga od twórcy generatora uprawnień, aby mógł on poprawnie działać.
 
<sourcesyntaxhighlight lang="php" line><?php
 
interface AclGeneratorInterface
Linia 66:
} // end isAllowed();
} // end AclSystem;
</syntaxhighlight>
</source>
 
Aby utworzyć interfejs, po słowie kluczowym '''interface''' wpisujemy jego unikalną nazwę, a następnie w nawiasach klamrowych wymieniamy listę wszystkich prototypów metod, których ma on dostarczać. Wszystkie metody interfejsu muszą być z założenia publiczne, dlatego nie można tu używać innych modyfikatorów dostępu, jednak powszechną konwencją jest dopisywanie słowa kluczowego '''public''' dla celów czytelności. Powyższy skrypt nie przedstawia póki co żadnej klasy, która by implementowała '''AclGeneratorInterface''', jednak mamy pokazany kod odpowiedzialny za jego wykorzystanie. Jak widać w linii 13, interfejsy mogą być stosowane do typowania argumentów, identycznie jak klasy. W naszym przykładzie chcemy mieć pewność, że wszystkie obiekty, które przekażemy jako argument do <code>loadGenerator()</code> posiadały metody <code>generate()</code> oraz <code>isAllowed()</code> bez względu na ich położenie w hierarchii klas.
Linia 74:
Zobaczmy teraz, jak zaimplementować interfejs w klasie tak, by PHP o tym wiedział. Napiszemy przykładowy generator, który wczyta uprawnienia z pliku.
 
<sourcesyntaxhighlight lang="php" line highlight="3"><?php
 
class FileGenerator implements AclGeneratorInterface
Linia 103:
} // end isAllowed();
} // end FileGenerator;
</syntaxhighlight>
</source>
 
Aby zaimplementować interfejs, wystarczy po nazwie klasy podać słowo kluczowe '''implements''' i wymienić listę interfejsów, oddzielając je przecinkami. Musimy pamiętać o następujących ograniczeniach:
Linia 113:
Poniżej pokazany jest przykład błędnego nazewnictwa metod:
 
<sourcesyntaxhighlight lang="php" line><?php
interface GooInterface
{
Linia 139:
} // end joe();
} // end GooInterface;
</syntaxhighlight>
</source>
 
Po uruchomieniu tego skryptu zobaczymy:
Linia 150:
Interfejsy można również dziedziczyć dokładnie tak samo, jak klasy, przy pomocy słowa kluczowego '''extends'''. Tutaj jednak wielokrotne dziedziczenie jest jak najbardziej dozwolone pod warunkiem, że nie ma konfliktów metod. Dziedziczenie interfejsów jest rzadko spotykane w rzeczywistych skryptach, lecz warto wiedzieć, że ono istnieje. Poniżej przedstawiony jest przykładowy skrypt pokazujący sposób wykorzystania i działanie:
 
<sourcesyntaxhighlight lang="php" line highlight="12"><?php
interface Foo
{
Linia 197:
echo 'Ten obiekt implementuje interfejs Joe<br/>';
}
</syntaxhighlight>
</source>
 
{{Uwaga|Dziedziczenie klas i interfejsów jest od siebie niezależne. Interfejs nie może dziedziczyć po klasie, a klasa po interfejsie, która może go jedynie implementować.}}
Linia 206:
W poprzednich rozdziałach poznaliśmy funkcję <code>sizeof()</code> (znaną też jako <code>count()</code>), która zwraca ilość elementów w tablicy. Może ona współpracować także z obiektami, zwracając ilość publicznych pól:
 
<sourcesyntaxhighlight lang="php" line><?php
class Counter
{
Linia 215:
$counter = new Counter;
echo sizeof($counter);
</syntaxhighlight>
</source>
 
Wiedza o ilości pól jest rzadko potrzebna w praktyce, jednak nic nie stoi na przeszkodzie, aby to przeprogramować. Tutaj przyda nam się pierwszy specjalny interfejs o nazwie <code>Countable</code>. Dostarcza on metodę <code>count()</code>, którą PHP wywołuje, gdy chce uzyskać informacje o ilości elementów.
Linia 221:
Pierwszym specjalnym interfejsem, jaki poznamy, jest '''Countable''', który dostarcza metodę <code>count()</code>. Informuje on interpreter, że klasa, która go implementuje, jest zbiorem elementów, które można policzyć (identycznie, jak elementy w tablicy). Rozbudujmy klasę '''Config''' z pierwszego rozdziału tak, aby można było uzyskać informacje o ilości aktualnie załadowanych opcji. Zakładamy, że wykonałeś ćwiczenie z poprzedniego rozdziału dotyczące jej rozbudowy:
 
<sourcesyntaxhighlight lang="php" line><?php
class Config implements Countable
{
Linia 234:
// pozostała część klasy
} // end Config;
</syntaxhighlight>
</source>
 
Teraz możemy prosto dowiedzieć się, ile opcji aktualnie znajduje się w konfiguracji:
 
<sourcesyntaxhighlight lang="php" line><?php
require('./Config.php');
$config = new Config;
echo 'Ilość elementów w konfiguracji: '.sizeof($config);
</syntaxhighlight>
</source>
 
Obiekty można jeszcze bardziej upodobnić do tablic dzięki interfejsowi '''ArrayAccess'''. Dostarcza on czterech metod:
Linia 253:
Aby przećwiczyć interfejsy w praktyce, cofnijmy się do przykładu z systemem formularzy z poprzedniego rozdziału. Do klasy abstrakcyjnej '''FormElement''' dodamy specjalne chronione pole <code>$_attributes</code> będące tablicą przechowującą dodatkowe atrybuty dla elementu formularza (np. klasa CSS, ID itd.). Klasa musi implementować interfejsy '''ArrayAccess''' oraz '''Countable''', które pozwolą na proste zarządzanie atrybutami tak, jakby obiekt elementu był tablicą. Zaimplementuj wszystkie wymagane metody tak, aby odpowiednio modyfikowały pole <code>$_attributes</code>. Zmodyfikuj klasy odpowiednich elementów tak, aby uwzględniały dodane atrybuty w generowanym kodzie HTML. Poniżej znajduje się przykładowy plik testowy:
 
<sourcesyntaxhighlight lang="php" line><?php
require('./FormElements.php');
Linia 269:
$form->display();
</syntaxhighlight>
</source>
 
Interfejsów specjalnych jest jeszcze więcej. Wśród nich specjalną grupę stanowią tzw. ''iteratory''. Poświęcimy im cały osobny rozdział.