En av de grundläggande egenskaperna hos objektorienterad programmering är **ärftlighet** och kapsling. Med dessa funktioner kan du enkelt bygga komplexa programlogiker samtidigt som du behåller en god läsbarhet.
Arv uttrycker att implementeringen av en klass bygger på en annan klass. I OOP-terminologi talar vi om descendant (den klass som ärver) och ancestor (den klass som vi ärver).
Generellt sett fungerar arv genom att den efterkommande får alla funktioner från den föregående, antingen genom att ta över dem exakt som den föregående hade dem, ändra dem på sitt eget sätt eller helt åsidosätta dem och använda sin egen implementering.
Användningen av detta tillvägagångssätt är mycket omfattande och arv används i ett antal designmönster.
Arv är väl lämpat för att utforma så kallade presenters, som är en speciell typ av klass som representerar länklogiken i designmönstret MVC.
Låt oss till exempel ha en trio med sidorna "Homepage", "Contact" och "Login".
När varje sida implementeras upprepas en stor del av logiken (t.ex. att ta emot en begäran, bygga upp URL:n, visa mallen och skicka in den resulterande HTML:n). Det är därför lämpligt att implementera en enda anförvant med denna logik och bara använda den i efterkommande.
Vi börjar med att först definiera anförvanten (klassnamnet spelar ingen roll, jag använder en konvention från Nette-ramverket):
abstract class BasePresenter{public function link(string $route, array $params = []): string{// implementering av metoden för att bygga upp webbadressen}public function renderTemplate(string $path, array $params = []): string{// logik för rendering av mallar}}
När jag definierade klassen använde jag det nya nyckelordet abstract
, som säger att klassen BasePresenter
är abstrakt. Det betyder att vi inte kan skapa en instans av den, utan bara behöver använda den så att en annan klass ärver och implementerar den. Abstraktion har andra användbara fördelar som vi kommer att diskutera senare. En klass behöver inte vara abstrakt för att vara ärftlig - det är bara en av de möjliga inställningarna.
Nu kan vi implementera en andra klass, till exempel HomepagePresenter
:
final class HomepagePresenter extends BasePresenter{public function run(): void{// logik för rendering$this->renderTemplate('hemsida', ['kontaktLänk' => $this->link('Kontakt:standard'),]);}}
Nu har du en fungerande klass HomepagePresenter
. Observera att klassen är final
, vilket innebär att den inte längre kan ärvas, vilket garanterar att metoderna kommer att användas exakt som vi specificerade dem.
När vi implementerade klassen skapade vi en ny "run()-metod som endast "HomepagePresenter" kan hantera. I metoden anropar vi metoden renderTemplate()
och link()
, som inte finns i klassen. Det spelar dock ingen roll, eftersom nyckelordet extends
talar om var metoderna ska ärvas från, så de används.
Tack vare arv kunde vi uppnå återanvändning av koden eftersom metoder som en gång skrivits kan användas på flera ställen.
Mycket ofta kan det vara användbart att åsidosätta beteendet hos en viss metod under arv. Om vi till exempel vill ändra beteendet hos metoden link()
från föregående exempel i ContactPresenter
skulle det se ut så här:
final class ContactPresenter extends BasePresenter{public function run(): void{// logik för renderingecho $this->link('Hemsida:standard', []);}public function link(string $route, array $params = []): string{return 'https://baraja.cz';}}
Om du vill åsidosätta implementeringen definierar du metoden i underobjektet igen och skriver över metodkroppen. Det viktiga är att gränssnittet är detsamma och att samma inmatningsargument används.
Ibland vill vi dölja vissa metoder under arv och använda dem endast internt. Alternativt kan du bara tillåta att de används vid arv och inte som ett offentligt gränssnitt.
I allmänhet finns det därför några enkla regler för synlighet. Vi betecknar metoder med public
, protected
eller private
, och reglerna för synlighet är följande:
link()
i det föregående exemplet).I mycket specifika fall kan det vara användbart att ändra synligheten för en metod vid körning och sedan anropa den. Detta används till exempel av olika Doctrine-bibliotek.
För att ändra synligheten använder vi sedan den inhemska klassen ReflectionClass som PHP självt har implementerat.
Jan Barášek Více o autorovi
Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.
Rád vám pomůžu:
Články píše Jan Barášek © 2009-2024 | Kontakt | Mapa webu
Status | Aktualizováno: ... | sv