Dědičnost tříd v PHP. Dědičnost v PHP. Volání metody supertřídy z podřízené třídy

Bootstrap framework: rychlé adaptivní rozložení

Videokurz krok za krokem o základech adaptivní rozložení v rámci Bootstrap.

Naučte se sázet jednoduše, rychle a efektivně pomocí výkonného a praktického nástroje.

Layout na objednávku a dostat zaplaceno.

Bezplatný kurz „Stránky na WordPressu“

Chcete ovládat WordPress CMS?

Získejte lekce o designu a rozložení webových stránek na WordPress.

Naučte se pracovat s motivy a stříhat rozvržení.

Zdarma video kurz kreslení návrhu webu, rozložení a instalace na CMS WordPress!

*Najetím myší pozastavíte rolování.

Zpět Vpřed

Dědičnost v PHP

Dědičnost je mechanismus, kterým lze z nějaké základní třídy odvodit jednu nebo více tříd.

Třída, která je získána zděděním od jiné, se nazývá její podtřída. Tento vztah se obvykle popisuje pomocí výrazů „rodič“ a „dítě“.

Podřízená třída je odvozena od nadřazené třídy a zdědí její vlastnosti. Tyto charakteristiky se skládají z vlastností a metod.

Podřízená třída obvykle přidává nové funkce do nadřazené třídy (také nazývané nadtřída). funkčnost. Proto se říká, že podřízená třída rozšiřuje nadřazenou třídu.

Než se začneme učit o syntaxi dědičnosti, podívejme se na problémy, které nám může pomoci vyřešit.


Problém dědičnosti

Vraťme se do třídy NakupovatProdukt. V současnosti je to dost zobecněné. S jeho pomocí si poradíte s nejrůznějším zbožím.

$product1 = new ShopProduct("Srdce psa", "Michail", "Bulgakov", 5,99); $product2 = new ShopProduct("Chybí", "Skupina", "DDT", 10,99); print "Autor: ".$product1->getProducer()."\n"; print "Producer: ".$product2->getProducer()."\n";

Výstup je následující.

Lenost je osobitá designová strategie, takže v této fázi nemusíte se starat o používání třídy NakupovatProdukt pro více než jeden typ produktu.

Pokud však v našem příkladu přidáme několik nových požadavků, vše se okamžitě zkomplikuje. Představte si, že potřebujeme zobrazit data specifická pro knihy a hudební alba.

Řekněme, že u alba je žádoucí zobrazit celkový čas zvuk a pro knihu - celkový počet stran. Samozřejmě mohou existovat i jiné rozdíly, ale ty dobře ilustrují podstatu problému.

Jak můžeme rozšířit náš příklad tak, aby vyhovoval těmto změnám? Hned mě napadají dvě možnosti. Nejprve můžete vložit všechna data do třídy NakupovatProdukt. Za druhé, můžete se zlomit NakupovatProdukt do dvou samostatných tříd.

Podívejme se na první přístup. Spojujeme tedy údaje o knihách a hudebních albech v jedné třídě.

Class ShopProduct ( veřejný $numPages; veřejný $playLength; veřejný $title; veřejný $producerMainName; veřejný $producerFirstName; veřejný $price; function __construct($title, $firstName, $mainName, $price, $numPages=0, $playLength= 0) ( $this->title = $title; $this->producerFirstName = $firstName; $this->producerMainName = $mainName; $this->price = $price; $this->numPages = $numPages; $this ->playLength = $playLength ) funkce getNumberOfPages() ( return $this->numPages; ) funkce getPlayLength() ( return $this->playLength; ) funkce getProducer() ( return "($this->producerFirstName)". " ($this->producerMainName)";

Chcete-li demonstrovat velké množství kódovací práce, v tomto příkladu byly použity metody přístupu k majetku $numPages A $playLength.

V důsledku toho bude objekt vytvořený pomocí takové třídy vždy obsahovat redundantní metody. U hudebního alba by navíc bylo potřeba vytvořit instanci objektu pomocí nesmyslného argumentu konstruktoru.

U alb se tedy budou ukládat informace o třídě a funkce související s knihami (celkový počet stránek) a u knih informace o době přehrávání alb.

Zatím se s tím asi dá žít. Ale co se stane, když přidáme více typů produkty, každý se svými vlastními metodami, a poté přidat více metod pro každý typ? Naše třída bude stále složitější a obtížněji použitelná.

Proto vynucení sloučení vlastností souvisejících s různé zboží, do jedné třídy povede k vytváření příliš těžkopádných objektů se zbytečnými vlastnostmi a metodami.

Tím ale problémy nekončí. Potíže budou také s funkčností.

Představte si metodu, která má výstupy stručné informace o produktu. Řekněme, že obchodní oddělení potřebuje jednořádkové informace o produktu pro použití na faktuře. Chtějí, abychom zahrnuli dobu přehrávání pro alba a počty stránek pro knihy.

Při implementaci této metody tedy budeme muset vzít v úvahu typ každého produktu. Ke sledování formátu objektu lze použít speciální příznak. Uveďme příklad.

Funkce getSummaryLine() ( $base = "($this->title) (($this->producerMainName), "; $base .= "($this->producerFirstName))"; if ($this->type = = "kniha") ( $base .= ": stránky - ($this->numPages)"; ) else if ($this->type == "cd") ( $base .= ": doba hraní - ($ this->playLength)"; ) return $base; )

Jak vidíte, správně nastavit hodnotu vlastnosti $typ, budeme muset zkontrolovat hodnotu argumentu v konstruktoru $numPages. A zase třída NakupovatProdukt se stala složitější, než je třeba.

Jak přidáváme další rozdíly ve formátech nebo nové formáty, budeme mít problém udržet krok s implementací této metody. Proto je zjevně k vyřešení tohoto problému nutné použít druhý přístup.

Od NakupovatProdukt začíná vypadat jako "dvě třídy v jedné", měli bychom to uznat a vytvořit dva typy místo jednoho. Zde je návod, jak na to.

Class CdProduct ( public $playLength; public $title; public $producerMainName; public $producerFirstName; public $price; function __construct($title, $firstName, $mainName, $price, $playLength) ( $this->title = $title $this->producerFirstName = $toto->producerMainName; $this->cena = $this->playLength() ( return $this->playLength; ) funkce getSummaryLine() ( $base = "; $this->title ($this->producerMainName, "; $base .= "$this->producerFirstName)"; $base .= ": doba hraní - $this-> playLength"; return $base; ) funkce getProducer () ( return "($this->producerFirstName)". " ($this->producerMainName)"; ) ) class BookProduct ( public $numPages; public $title; public $producerMainName ; public $producerFirstName; public $price; function __construct($title, $firstName, $mainName, $price, $numPages) ( $this->title = $title; $this->producerFirstName = $firstName; $this-> producentMainName = $mainName;

$tato->cena = $cena;

Nyní můžeme vytvořit metodu getSummaryLine() pro každý typ produktu a nemusíme ani kontrolovat hodnotu speciálního příznaku. A žádná jiná třída neobsahuje pole (vlastnosti) nebo metody, které s ní nesouvisí.

A obětí byla duplikace. Metody getProducer() naprosto stejné pro každou třídu. Každý konstruktor nastavuje stejným způsobem řadu identických vlastností. To je další známka špatného vkusu a musíte se naučit, jak se ho zbavit.

V případě potřeby oba způsoby getProducer() fungovaly stejně pro každou třídu, pak jakékoli změny provedené v jedné implementaci musí být provedeny ve druhé. Tímto způsobem ale brzy rozbijeme synchronizaci tříd.

I když jsme si jisti, že dokážeme zachovat duplicitu, naše problémy tím nekončí. Koneckonců, nyní máme dva typy, nejen jeden.

Pamatujte na třídu ShopProductWriter? Jeho metoda napsat() navrženo pro práci s jedním typem: NakupovatProdukt. Jak z této situace ven, aby vše fungovalo jako doposud?

Můžeme odstranit kvalifikaci typu třídy z deklarace metody, ale pak musíme doufat, že metoda napsat() bude předán objekt správného typu.

Můžeme přidat do těla metody vlastní kód pro kontrolu typu.

Třída ShopProductWriter ( veřejná funkce write($shopProduct) ( if (! ($shopProduct instanceof CdProduct) && ! ($shopProduct instanceof BookProduct)) ( die("Neplatný datový typ předán"); ) $str = "($shopProduct-> title): " . $shopProduct->getProducer() ." (($shopProduct->price))\n"; tisk $str; ) )

Věnujte pozornost operátorovi instanceof, použitý v tomto příkladu. Místo toho je nahrazena hodnota věrný(true), pokud je objekt v operandu vlevo typu reprezentovaného operandem vpravo.

A opět jsme byli nuceni přidat nová úroveň složitost. Musíme nejen zkontrolovat argument $shopProdukt pro shodu se dvěma typy v metodě napsat(), ale také doufáme, že každý typ bude podporovat stejná pole a metody jako druhý.

Souhlasíte, mít pouze jeden typ by bylo mnohem lepší, protože bychom mohli použít upřesnění typu třídy pro argument metody napsat(), a byli bychom si jisti, že tř NakupovatProdukt podporoval specifické rozhraní.

Vlastnosti třídy NakupovatProdukt, spojené s knihami a hudebními alby, nefungují dobře dohromady, ale zdá se, že nemohou existovat samostatně.

Musíme s knihami a alby zacházet jako s jedním typem, ale zároveň musíme pro každý výstupní formát poskytnout samostatnou implementaci metody.

Musíme vytvořit společnou funkcionalitu na jednom místě, abychom se vyhnuli duplicitě, ale zároveň dbát na to, aby při volání metody, která zobrazuje stručné informace o produktu, byly zohledněny funkce formátování. Zkrátka musíme použít dědičnost.

P.S. Zjevně chcete rozumět PHP a OOP) Věnujte pozornost prémiovým lekcím na různé aspekty tvorba webových stránek včetně programování v PHP, stejně jako volný kurz o vytvoření vlastního CMS systému v PHP od nuly pomocí OOP:

Líbil se vám materiál a chcete mi poděkovat?
Stačí sdílet se svými přáteli a kolegy!


Dědičnost je objektový mechanismus orientované programování, což nám umožňuje popsat nová třída na základě existujícího (rodičovského).

Třída, která je získána zděděním od jiné, se nazývá podtřída. Tento vztah se obvykle popisuje pomocí výrazů „rodič“ a „dítě“. Podřízená třída je odvozena od nadřazené třídy a zdědí její vlastnosti: vlastnosti a metody. Obvykle podtřída přidává nové funkce k funkčnosti nadřazené třídy (také nazývané nadtřída).

Chcete-li vytvořit podtřídu, musíte v deklaraci třídy použít klíčové slovo extends následované názvem třídy, ze které dědíte:

věk = $věk;
) funkce add_age () ( $this->age++; ) ) // deklarujeme zděděnou třídu class my_Cat extends Cat ( // definuje naši vlastní metodu podtřídy function sleep() ( echo "

Zzzzz..."; ) ) $kitty = new my_Cat(10); // volání zděděné metody $kitty->add_age(); // čtení hodnoty zděděné vlastnosti echo $kitty->age; // volání vlastní metoda podtřídy $ kitty->sleep();

Podtřída dědí přístup ke všem metodám a vlastnostem nadřazené třídy, protože jsou typu public . To znamená, že pro instance třídy my_Cat můžeme volat metodu add_age() a přistupovat k vlastnosti $age, i když jsou definovány ve třídě cat. Také ve výše uvedeném příkladu podtřída nemá svůj vlastní konstruktor. Pokud podtřída nedeklaruje svůj vlastní konstruktor, pak se při vytváření instancí podtřídy automaticky zavolá konstruktor nadtřídy.

věk"; ) ) třída moje_kočka rozšiřuje Cat (veřejný $věk = 10; ) $koťátko = nová moje_kočka; $koťátko->foo(); ?>

Při volání $kitty->foo() nemůže PHP interpret takovou metodu najít ve třídě my_Cat, proto je použita implementace této metody definované ve třídě Cat. Podtřída však definuje svou vlastní vlastnost $age, takže když se k ní přistoupí pomocí metody $kitty->foo(), interpret PHP najde tuto vlastnost ve třídě my_Cat a použije ji.

Vzhledem k tomu, že téma zadávání typu argumentů jsme již probrali, zbývá říci, že pokud je jako typ uvedena nadřazená třída, pak budou k dispozici pro použití i všichni potomci metody, podívejte se na následující příklad:

foo(new my_Cat); ?>

S instancí třídy my_Cat můžeme zacházet, jako by se jednalo o objekt typu Cat, tzn. můžeme předat objekt typu my_Cat metodě foo() třídy Cat a vše bude fungovat podle očekávání.

nadřazený operátor

V praxi může být nutné, aby podtřídy rozšířily funkčnost metod rodičovské třídy. Rozšířením funkčnosti přepsáním metod nadtřídy si v podtřídách zachováte možnost prvního spuštění programový kód rodičovskou třídu a poté přidejte kód, který implementuje další funkce. Podívejme se, jak to lze provést.

Zavolat požadovanou metodu z nadřazené třídy, budete muset přistupovat k této třídě samotné prostřednictvím deskriptoru. PHP pro tento účel poskytuje nadřazené klíčové slovo. Rodičovský operátor umožňuje podtřídám přistupovat k metodám (a konstruktorům) nadřazené třídy a přidávat k jejich stávající funkčnosti. Chcete-li odkazovat na metodu v kontextu třídy, použijte symboly "::" (dvě dvojtečky). Syntaxe nadřazeného operátoru je:

Parent::parent_class metoda

Tato konstrukce zavolá metodu definovanou v nadtřídě. Po takovém volání můžete umístit svůj programový kód, který přidá nové funkce:

titulek = $titul;
$tato->cena = $cena;
) ) class new_book extends book ( public $pages; funkce __construct($title, $price, $pages) ( // volání metody konstruktoru rodiče rodičovské třídy::__construct($title, $price); // inicializuje vlastnost definovaná v podtřídě $this->pages = $pages ) ) $obj = new new_book("ABC", 35, 500);

Když podřízená třída definuje svůj vlastní konstruktor, PHP automaticky nevolá konstruktor nadřazené třídy. To je nutné provést ručně v konstruktoru podtřídy. Podtřída nejprve zavolá konstruktor své nadřazené třídy ve svém konstruktoru, předá potřebné argumenty pro inicializaci, provede ji a poté provede kód, který implementuje další funkce, v v tomto případě inicializuje vlastnost podtřídy.

Klíčové slovo parent lze použít nejen v konstruktorech, ale také v jakékoli jiné metodě, jejíž funkčnost chcete rozšířit, toho lze dosáhnout voláním metody nadřazené třídy:

jméno)."; return $str; ) ) class my_Cat rozšiřuje Cat ( public $age = 5; funkce getstr() ( $str = parent::getstr(); $str .= "
Věk: ($this->age) years."; return $str; ) ) $obj = new my_Cat; echo $obj->getstr(); ?>

Zde se nejprve zavolá metoda getstr() z nadtřídy, jejíž hodnota se přiřadí proměnné, a poté se provede zbytek kódu definovaného v metodě podtřídy.

Nyní, když jsme probrali základy dědičnosti, můžeme se konečně podívat na problematiku viditelnosti vlastností a metod.

veřejné, chráněné a soukromé: řízení přístupu

Až do tohoto okamžiku jsme výslovně deklarovali všechny vlastnosti jako veřejné. A tento typ přístupu je standardně nastaven pro všechny metody.

Členy třídy lze deklarovat jako veřejné, chráněné nebo soukromé. Podívejme se na rozdíl mezi nimi:

  • NA veřejnost(veřejné) vlastnosti a metody jsou přístupné z jakéhokoli kontextu.
  • NA chráněný(chráněné) vlastnosti a metody jsou přístupné buď z obsahující třídy, nebo z její podtřídy. Žádný externí kód přístup k nim není zajištěn.
  • Data třídy můžete znepřístupnit volací program pomocí klíčového slova soukromé(ZAVŘENO). K takovým vlastnostem a metodám lze přistupovat pouze z třídy, ve které jsou deklarovány. Ani podtřídy této třídy nemají k takovým datům přístup.

veřejný - otevřený přístup:

ahoj"; ) ) $obj = nový člověk; // přístup z volajícího programu echo "$obj->age"; // Platné $obj->say(); // Platné?>

private - přístup pouze z metod třídy:

věk"; ) ) $obj = nový člověk; // není přímý přístup k soukromým datům z volajícího programu echo "$obj->age"; // Chyba! přístup odepřen! // pomocí metody však můžete zobrazit soukromá data $obj ->say( // Přijatelné?>);

chráněný - chráněný přístup:

Chráněný modifikátor vypadá z pohledu volajícího programu úplně stejně jako soukromý: zakazuje přístup k datům objektu zvenčí. Na rozdíl od soukromých vám však umožňuje přistupovat k datům nejen z metod vaší třídy, ale také z metod podtřídy.

Toto je druhá část našeho tutoriálu o objektech v PHP. První část je zde: objekty v PHP.

Co je dědičnost v PHP

Pomocí dědičnosti můžeme vytvořit třídy, které budou obsahovat všechny vlastnosti a metody rodičovské třídy. Tedy dětské třídy zdědit vlastnosti a metody nadřazené třídy.

Podřízená třída je rozšířením nadřazené třídy, protože kromě zděděných vlastností a metod obsahuje i své vlastní.

Dědičnost je stanovena použitím slova extends při vytváření třídy.

Jednoduchý příklad:

jméno, věk: $this->age, "; ) ) class Son extends Dad // Son in American - syn, dědic třídy Dad (otec) ( public $user = "Hezčí", $password = "secretNic"; public function printUserInfo() ( echo "login: $toto->uzivatel, heslo: $toto->heslo."; ) ) $obj = new Son(); $obj->printUserInfo(); );

Jak vidíte, pracujeme pouze s instancí podřízené třídy Son, ale jejím prostřednictvím přistupujeme k metodě printInfo() nadřazené třídy Dad. To je význam dědičnosti v PHP.

Slovo extends je doslovně přeloženo z angličtiny jako expandovat. Takže psaní „třída Syn rozšiřuje tátu“ je velmi snadné pochopit, konkrétně: „třídní syn rozšiřuje (třídu) tátu“.

Příklad třídní dědičnosti

Poslední lekci jsme dokončili pomocí příkladu třídy:

id = $id;

$this->type = "kniha";

Dědičnost v PHP id = $id;

$this->type = "kniha";

$this->name = "Válka a mír";

$this->description = "Tlustá kniha o několika svazcích";

$this->price = "543,26";

) ) class GoodsInfo rozšiřuje Zboží ( funkce printGoods() ( echo "ID produktu: $this->id. Typ produktu: $this->type. Název: \"$this->name\". Popis: $this-> popis. Cena: $tato->cena."; ) ) $Zboží = new Info o zboží(124); $Zboží->tiskZboží();

V tomto příkladu je druhá třída GoodsInfo deklarována pomocí klíčového slova extends, což znamená, že jde o dědice třídy, jejíž jméno je uvedeno níže, v našem případě třídy Goods.

Třída Informace o zboží se nazývá podřízená třída a třída Zboží se nazývá nadřazená třída. Taková jména naznačují dědičný vztah těchto tříd.

V podřízené třídě GoodsInfo máme přístup ke všem vlastnostem a metodám nadřazené třídy.

Protože třída GoodsInfo nemá svůj vlastní konstruktor, je automaticky spuštěn nadřazený konstruktor. Pokud má podřízená třída konstruktor, nadřazený konstruktor se nespustí.

Dědičnost v PHP Napíšu znovu: ve skutečnosti je dětská třída rozšířením rodičovské třídy. Klíčové slovo extends, které označuje vztah, je z angličtiny přeloženo jako rozšíření.

To znamená, že můžeme vytvořit třídu, která je úložištěm informací, a vytvořit několik podřízených tříd, které tyto informace zpracovávají, přičemž každá třída se specializuje na svůj vlastní úkol.

Vyjasnění typů objektů

Metoda printGoods() by měla jako vstup obdržet pouze objekt třídy Zboží a my bychom to opravdu rádi prověřili. Zkontrolujeme to takto:

Veřejná funkce printGoods(Goods $Goods) // metoda by měla obdržet objekt ( echo " ID produktu: $Goods->id. Typ produktu: $Goods->type. Name: \"$Goods->name\". Popis : $ Zboží->popis Cena: $Zboží->cena "; )

Řádek printGoods(Goods $Goods) , nejprve přichází název třídy, které musí odpovídat objekt argumentu, a poté argument. Pokud je metodě předán argument elementárního typu (řetězec, celé číslo, float, boolean) nebo objekt jiného typu, dojde k chybě.

Použití této techniky je z hlediska zabezpečení skriptů velmi správné.

Tímto způsobem můžete zkontrolovat typy objektů a pole, zde je syntaxe pro kontrolu polí:

veřejná funkce tisk Zboží(pole $Zboží) (...)

A řetězce a další elementární typy je třeba kontrolovat pomocí speciálních funkcí.

Můžete také požadovat, aby argument byl buď určitý typ nebo nulová hodnota(NULL).

veřejná funkce printGoods(pole $Goods=null) (...)

Rozsah v PHP

Nyní můžeme téma rozsahu vlastností a metod uzavřít. Jsou tři klíčová slova, definovat různé rozsahy.

  • veřejné – dostupné všem.
  • chráněné – dostupné pro tuto třídu a její děti, stejně jako jejich předměty.
  • soukromé - není dostupné ani pro dětské třídy.

Všechno je to o rozsahu.

Práce s dědičností v PHP

Z podřízené třídy můžete volat metodu v nadřazené třídě. K tomu se používá deskriptor (v angličtině - parent).

Dědičnost v PHP id = $id;

$this->type = "kniha";

$this->name = "Válka a mír";

$this->description = "Tlustá kniha o několika svazcích";

Dědičnost v PHP

Nejprve napíšeme název třídy, poté dvojtečku a poté metodu.

Resumé

Takže jsme studovali mechanismus dědičnosti. Samozřejmě je toho ještě hodně ke studiu, tyto informace jsou pouze úvodní.

Pokračujme další lekcí:

V tomto tutoriálu si povíme něco o dědění v OOP a jak to funguje v PHP. Pomocí dědičnosti můžete třídy učinit mnohem silnějšími a flexibilnějšími a také ušetřit spoustu času psaním skriptů.

Podíváme se na následující:

  • Pojem dědictví a proč je užitečné jej používat;
  • Jak může jedna třída PHP dědit od druhé;
  • Jak může jedno z „dětí“ třídy přetížit funkčnost svých „rodičovských“ metod;
  • Práce se závěrečnými metodami a třídami;
  • Použití abstraktních tříd;
  • Práce s rozhraními.

Jste připraveni? Tak do toho!

Jak se dědění provádí?

Dědičnost je založena na konceptech rodičovské třídy a nástupnické třídy. Pomocí určité syntaxe můžete vytvořit třídu, která bude dědit od jiné třídy (stane se jejím potomkem).

Poznámka: Nadřazené třídy se také nazývají základní třídy nebo supertřídy. Dědit třídy lze zase nazývat podtřídy nebo podtřídy.

Když vytvoříte podřízenou třídu, zdědí všechna pole a metody své základní třídy. Do podřízené třídy můžete přidat další pole a metody, čímž rozšíříte funkčnost nadřazené třídy.

Například ve webové aplikaci fóra existuje třída Member, která má metody createPost(), editProfile(), showProfile() atd. Protože jejími členy jsou také administrátoři fóra, můžete vytvořit třídu Administrator – potomka třídy Členská třída. Třída Administrator dědí všechna pole a metody třídy Member, což znamená, že objekt třídy Administrator se bude chovat přesně jako objekt Member.

Funkčnost třídy Administrator můžete rozšířit přidáním metod, jako je createForum(), deleteForm() a banMember(). A pokud chcete administrátorům přiřadit role, přidejte do této podřízené třídy pole, například $adminLevel.

Tím se vyhnete zahlcení třídy Member metodami a poli, které nejsou vhodné pro běžné členy fóra, ale pouze pro administrátory. Také nebudete muset kopírovat a vkládat metody a pole ze třídy Člen do podřízené třídy. Takže dědičnost je pro vás ideální.

Poznámka: Z jedné supertřídy můžete vytvořit tolik podřízených tříd, kolik potřebujete, a do každé z nich můžete přidávat další a další metody a pole.

Vytváření dětských tříd

Jak tedy vytvoříte třídu, která zdědí jinou třídu v PHP? K tomu existuje rozšíření klíčových slov:

Třída ParentClass ( // popis polí a metod ) třída ChildClass rozšiřuje ParentClass ( // popis dalších polí a metod )

Vytvořili jsme třídu ParentClass a poté třídu ChildClass, která dědí z ParentClass. ChildClass dědí všechna pole a metody třídy ParentClass a můžete do ní také přidat svá vlastní pole a metody.

A teď - příklad. Vytvořme třídu Member pro imaginární webové fórum a poté vytvořte třídu Administrator, potomka třídy Member:

Člen třídy ( public $username = ""; private $loggedIn = false; veřejná funkce login() ( $this->loggedIn = true; ) veřejná funkce logout() ( $this->loggedIn = false; ) veřejná funkce isLoggedIn( ) ( return $this->loggedIn; ) ) class Administrátor rozšiřuje Člena ( veřejná funkce createForum($forumName) ( echo "$this->username vytvořilo nové fórum: $forumName
"; ) public function banMember($member) ( echo "$this->username zakázala člen: $member->username
"; } }

Jak můžete vidět, třída Member obsahuje veřejné pole $username a soukromé pole $loggedIn, stejně jako metody pro přihlášení a odhlášení z fóra a metodu pro zjištění, zda je uživatel přihlášen nebo ne.

  • createForum($forumName) pro vytvoření nového fóra s názvem $forumName;
  • banMember($member) zakáže uživateli $member.

Poznámka: Tyto metody přirozeně nic nedělají, protože naše fórum je imaginární. Jednoduše zobrazí nějaké zprávy na stránce.

Pojďme se podívat na naše třídy v akci. Vytvořme jeden objekt z obou tříd a pak zavolejte některé z jejich metod:

// vytvořte člena fóra a přihlaste ho $member = new Member(); $member->username = "Fred"; $member->login(); echo $member->username . "je". ($member->
"; // vytvořte správce a přihlaste ho $admin = new Administrator(); $admin->username = "Mary"; $admin->login(); echo $admin->username . " is " . ($ member- >isLoggedIn() ? "přihlášeno" : "odhlášeno") "
"; // zobrazí "Mary vytvořila nové fórum: Teddy Bears" $admin->createForum("Teddy Bears"); // zobrazí "Mary zakázala člena: Fred" $admin->banMember($member);

Na stránce se zobrazí:

Fred je přihlášen Mary je přihlášen Mary vytvořil nové fórum: Teddy Bears Mary zabanovala člena: Fred

Funguje to takto:

  1. Nejprve jsme vytvořili objekt třídy Member, nastavili uživatelské jméno na „Fred“, přihlásili jsme ho a na stránce jsme zobrazili zprávu, že je přihlášen do fóra.
  2. Poté vytvoříme objekt třídy Administrator. Protože tato třída dědí z Member, můžeme pro objekty třídy Administrator použít všechny metody a pole této třídy. Administrátorovi dáme jméno - Mary - a přihlásíme ji, načež se zobrazí zpráva, že je přihlášena.
  3. Nyní zavoláme metodu createForum() třídy Administrator a předáme jí název fóra – „Teddy Bears“.
  4. Nakonec zavoláme metodu banMember() z objektu admin a předáme uživatelské jméno Fred.

To je podstata dědičnosti v OOP. Později v lekci se podíváme na různé způsoby manipulace s dědičností, včetně přetěžování, konečných tříd a metod, abstraktních tříd a rozhraní.

Přetížení rodičovských metod

Jak jste již viděli, když vytvoříte podřízenou třídu, zdědí všechna pole a metody své nadřazené třídy. Může však být nutné změnit funkčnost metod supertřídy v podřízené třídě.

Použijeme-li fórum jako příklad: když se admin přihlásí, děje se to úplně stejným způsobem jako u běžného uživatele, ale možná budete chtít zapsat protokoly do konkrétního souboru z bezpečnostních důvodů.

Přetížením metody login() v podřízené třídě můžete tuto metodu změnit podle svých představ.

Chcete-li přetížit metodu supertřídy v podřízené třídě, jednoduše vytvořte metodu se stejným názvem. Potom při volání metody pro objekty podřízené třídy bude volána přetížená metoda, nikoli metoda supertřídy:

Třída ParentClass ( veřejná funkce myMethod() ( // (akce) ) ) třída ChildClass rozšiřuje ParentClass ( veřejná funkce myMethod() ( // volaná na objektu ChildClass // místo metody supertřídy MyMethod()) )

Pojďme přetížit metodu login() pro třídu Administrator tak, aby se protokoly zapisovaly do souboru:

Člen třídy ( public $username = ""; private $loggedIn = false; veřejná funkce login() ( $this->loggedIn = true; ) veřejná funkce logout() ( $this->loggedIn = false; ) ) správce třídy rozšiřuje Člen ( public function login() ( $this->loggedIn = true; echo "Záznam protokolu: $this->username přihlášen
"; ) ) // vytvořte nového uživatele a přihlaste ho $member = new Member(); $member->username = "Fred"; $member->login(); $member->logout(); // vytvořit nového správce a přihlásit se $admin = new Administrator(); $admin->login(); $admin->logout(); );

Jak můžete vidět, přetížili jsme metodu login() třídy Administrator tak, aby zobrazovala zprávy jako v souborech protokolu.

Poté jsme vytvořili běžného uživatele (Fred) a správce (Mary). Volání Fredovy metody login() volá Member::login(). A když zavoláme metodu od administrátora Mary, zavolá se metoda Administrator::login(), protože PHP vidí, že jsme tuto metodu pro tuto třídu přetížili. Na stránce se zobrazí řádek „Záznam protokolu: Marie přihlášena“.

Na druhou stranu jsme nepřetížili metodu logout() v podřízené třídě, takže Member:logout() se volá jak pro administrátory, tak pro běžné uživatele.

Volání metody supertřídy z podřízené třídy

Když přetížíte metodu v podřízené třídě, obvykle nemusíte měnit celou metodu. Budete muset použít funkcionalitu metody super class a přidat nějaké věci do metody podřízené třídy.

V příkladu uvedeném v posledním odstavci jsme přetížili metodu login(). Ale duplikovali jsme část metody Member::login() v Administrator::login():

Správce třídy rozšiřuje člena ( public function login() ( $this->loggedIn = true; echo "Záznam protokolu: $this->username přihlášen
"; } }

Místo duplikování kódu je lepší zavolat metodu Member::login() z Administrator::login().

Chcete-li získat přístup k metodě supertřídy z podřízené třídy, použijte nadřazené klíčové slovo:

Parent::myMethod();

Pojďme nyní přepsat metodu login() v podřízené třídě tak, aby volala stejnou metodu v nadřazené třídě, a pak do ní přidejte něco nového:

Správce třídy rozšiřuje člena ( public function login() ( parent::login(); echo "Záznam protokolu: $this->username přihlášen
"; } }

To nejen zkracuje kód, ale také usnadňuje budoucí úpravy. Pokud později budete potřebovat změnit způsob přihlašování libovolného uživatele, budete muset upravit pouze metodu login() ve třídě Member a třída Administrator zavolá již upravenou metodu.

Předcházení dědičnosti pomocí konečných metod a tříd

Ve většině případů je dobrou praxí umožnit třídám rozšířit jejich funkčnost prostřednictvím dědičnosti. To je součástí síly OOP.

Stává se však, že přetěžování metod supertříd může vést k problémům, snížit bezpečnost a zkomplikovat kód. V těchto případech by bylo užitečné zakázat dědění metody nebo dokonce celé třídy.

Chcete-li zabránit podřízeným třídám v přetížení metod supertřídy, přidejte klíčové slovo final před jeho deklaraci. Můžete například chtít zabránit přetížení metody login() třídy členů z bezpečnostních důvodů:

Člen třídy ( public $username = ""; private $loggedIn = false; veřejná závěrečná funkce login() ( $this->loggedIn = true; ) veřejná funkce logout() ( $this->loggedIn = false; ) veřejná funkce isLoggedIn () ( return $this->loggedIn; ) )

Pokud se někdo pokusí zdědit třídu a přetížit tuto metodu:

Třída NaughtyMember rozšiřuje člena ( public function login() ( $this->loggedIn = true; // udělat něco špatného ) )

... PHP vypíše chybovou zprávu:

Závažná chyba: Nelze přepsat konečnou metodu Member::login()

Můžete také zakázat dědění z celé třídy:

Final class Member ( // z této třídy nemůžete vůbec dědit )

Jakýkoli pokus o vytvoření podřízené třídy této třídy selže:

Závažná chyba: Třída NaughtyMember nemusí dědit z poslední třídy (člen)

Poznámka: Přestože se jedná spíše o Javu než o PHP, zdůrazňuje výhody použití finálních metod a tříd.

Práce s abstraktními třídami

Abstraktní třída je třída, která nemůže být konkretizována, to znamená, že nemůžete vytvořit objekt třídy, pokud je abstraktní. Místo toho z něj vytvoříte podřízené třídy a potichu vytvoříte objekty z těchto podřízených tříd. Abstraktní třídy jsou šablony pro vytváření tříd.

Abstraktní třída obsahuje jednu nebo více abstraktních metod. Když vytvoříte abstraktní metodu v abstraktní třídě, nepřidáte k této metodě nic. Místo toho musí být deklarován v jakékoli podřízené třídě.

Poznámka: Jakmile vytvoříte alespoň jednu abstraktní metodu ve třídě, musíte tuto třídu deklarovat jako abstraktní.

Když běžná třída dědí z abstraktní třídy, musí implementovat všechny abstraktní metody rodičovské třídy. V opačném případě PHP vygeneruje chybu. Abstraktní třída tedy vytváří „pravidla chování“ pro své podřízené třídy.

Poznámka: Do abstraktní třídy můžete přidat neabstraktní metody. Budou je zdědit dětské třídy jako obvykle.

Podívejme se na příklad. Řekněme, že vytváříme webovou stránku, která má členy fóra i kupující internetového obchodu, který je součástí našeho webu. Protože jak účastníci fóra, tak kupující jsou lidé, můžeme vytvořit abstraktní třídu Person, která bude mít některá pole a metody společné pro všechny uživatele webu:

Abstraktní třída Osoba ( private $firstName = ""; private $lastName = ""; veřejná funkce setName($firstName, $lastName) ( $this->firstName = $firstName; $this->lastName = $lastName; ) veřejná funkce getName() ( return "$this->firstName $this->lastName"; ) abstraktní veřejná funkce showWelcomeMessage();

Jak můžete vidět, vytvořili jsme abstraktní třídu přidáním klíčového slova abstract do jejího popisu. Tato třída má několik vlastností společných všem lidem – $frstName a $lastName – a také metody pro inicializaci a čtení hodnot těchto polí.

Třída má také abstraktní metodu showWelcomeMessage(). Tato metoda zobrazí pozdrav, když uživatel vstoupí na web. Opět do popisu této metody přidáme klíčové slovo abstract, aby byla abstraktní. Jelikož je abstraktní, není v něm jediný řádek kódu, je to jen jeho deklarace. K přidání a definování metody showWelcomeMessage() je však vyžadována jakákoli podřízená třída.

Nyní vytvoříme několik tříd z abstraktní třídy Person:

  1. Členská třída pro členy fóra;
  2. Třída Shopper pro kupující v internetových obchodech.

Člen třídy rozšiřuje osobu ( veřejná funkce showWelcomeMessage() ( echo "Ahoj " . $this->getName() . ", vítejte na fóru!
"; ) public function newTopic($subject) ( echo "Vytváření nového tématu: $předmět
"; ) ) class Shopper rozšiřuje Osoba ( veřejná funkce showWelcomeMessage() ( echo "Ahoj " . $this->getName() . ", vítejte v našem online obchodě!
"; ) public function addToCart($item) ( echo "Přidávání $položky do košíku
"; } }

Jak vidíte, každý z nich popisuje metodu showWelcomeMessage() z abstraktní supertřídy. Jsou implementovány odlišně: třída Member zobrazuje zprávu „vítejte ve fóru“ a třída Shopper zobrazuje „vítejte v našem internetovém obchodě“, ale to je normální. Hlavní věc je, že oba tuto metodu popsali.

Pokud by jeden z nich, jako Shopper, nepopsal metodu, PHP by vyvolalo chybu:

Spolu s implementací abstraktní metody má každá třída své vlastní pravidelné metody. Člen má metodu newTopic() pro vytvoření nového tématu fóra a Shopper má metodu addToCart() pro přidávání položek do košíku.

Nyní můžeme na našich stránkách vytvářet členy fóra a kupující. U těchto objektů můžeme volat metody newTopic() a addToCart() a také getName() a setName(), protože dědí z nadtřídy Person.

Navíc s vědomím, že třídy Member a Shopper dědí z Person, můžeme bezpečně volat metodu showWelcomeMessage() na obě třídy, protože je přesně implementována v obou. Jsme si tím jisti, protože víme, že byla deklarována jako abstraktní metoda ve třídě Person.

Zde je příklad:

$aMember = nový člen(); $aMember->setName("John", "Smith"); $aMember->showWelcomeMessage(); $aMember->newTopic("Medvídci jsou skvělí"); $aShopper = new Shopper(); $aShopper->setName("Mary", "Jones"); $aShopper->showWelcomeMessage(); $aShopper->addToCart("Ozdobená stolní lampa");

Na stránce se zobrazí:

Ahoj Johne Smithi, vítejte na fóru! Zakládání nového tématu: Medvídci jsou skvělí Ahoj Mary Jones, vítejte v našem internetovém obchodě! Přidání zdobené stolní lampy do košíku

Vytváření a používání rozhraní

Rozhraní jsou v mnoha ohledech podobná abstraktním třídám. Rozhraní je šablona, ​​která definuje chování jedné nebo více tříd.

Zde jsou hlavní rozdíly mezi rozhraními a abstraktními třídami:

  1. V rozhraní nelze popsat žádnou metodu. Všechny jsou abstraktní. Abstraktní třída může mít neabstraktní metody.
  2. Rozhraní nemůže obsahovat pole – pouze metody.
  3. Třída implementuje rozhraní a třída zdědí nebo rozšiřuje jinou třídu.
  4. Třída může implementovat několik rozhraní současně. Stejná třída může dědit z jiné třídy. Ale podřízená třída může mít pouze jednu super třídu (abstraktní nebo ne).

Stejně jako abstraktní třída rozhraní deklaruje několik metod, které musí být implementovány v jakékoli třídě, která implementuje rozhraní. Syntaxe vypadá takto:

Rozhraní MyInterface ( veřejná funkce aMethod(); veřejná funkce otherMethod(); )

Chcete-li vytvořit třídu, která implementuje konkrétní rozhraní, napište toto:

Třída MyClass implementuje MyInterface ( veřejná funkce aMethod() ( // (implementace metody) ) veřejná funkce otherMethod() ( // (implementace metody) ) )

Rozhraní jsou užitečná, když potřebujete vytvořit několik nesouvisejících tříd, které sdílejí společné funkce.

Webové fórum může například obsahovat třídu Member pro členy fóra a třídu Téma pro témata vytvořená členy fóra. Pokud jde o dědičnost, tyto třídy na sobě s největší pravděpodobností nebudou záviset, protože plní zcela odlišné funkce.

Předpokládejme však, že je budeme muset získat a zapsat do databáze objekty Member i Topic. K tomu vytvoříme Persistable rozhraní, které bude mít metody pro ukládání objektů do databáze a jejich načítání odtud:

Trvalé rozhraní ( public function save (); public function load (); public function delete (); )

Nyní vytvoříme třídu Member a implementujeme pro ni rozhraní Persistable. To znamená, že rozhraní musí mít metody save(), load() a delete():

Člen třídy implementuje Persistable ( soukromé $username; private $location; private $homepage; veřejná funkce __construct($username, $location, $homepage) ( $this->username = $username; $this->location = $location; $ this->homepage = $homepage; ) veřejná funkce getUsername() ( return $this->username; ) veřejná funkce getLocation() ( return $this->location; ) veřejná funkce getHomepage() ( return $this->homepage; ) public function save() ( echo "Ukládání člena do databáze
"; ) public function load() ( echo "Načítání člena z databáze
"; ) public function delete () ( echo "Mazání člena z databáze
"; } }

Naše třída Téma bude také implementovat toto rozhraní, takže by měla mít také tyto tři metody:

Téma třídy implementuje Persistable ( soukromý $předmět; soukromý $autor; soukromý $createdTime; veřejná funkce __construct($předmět, $autor) ( $this->předmět = $předmět; $this->autor = $autor; $this-> createdTime = time( ) veřejná funkce showHeader() ( $createdTimeString = date("l jS M Y h:i:s A", $this->createdTime); $authorName = $this->author->getUsername() echo "$this->předmět (vytvořeno $createdTimeString $authorName)
"; ) public function save() ( echo "Ukládání tématu do databáze
"; ) public function load() ( echo "Načítání tématu z databáze
"; ) public function delete () ( echo "Mazání tématu z databáze
"; } }

Poznámka: Protože je naše fórum imaginární, namísto interakce s databází metody save(), load() a delete() jednoduše zobrazují zprávy.

Nyní můžeme vytvořit objekty tříd Member a Topic a pak volat jejich metody getUsername() a showHeader(). Navíc s vědomím, že tyto třídy implementují rozhraní Persistable, můžeme volat metody jako save(), load() nebo delete():

$aMember = new Member("fred", "Chicago", "http://example.com/"); echo $aMember->getUsername() . "žije v" $aMember->getLocation() ."
"; $aMember->save(); $aTopic = new Topic("Medvídci jsou skvělí", $aMember); $aTopic->showHeader(); $aTopic->save();

Na stránce se zobrazí:

Fred žije v Chicagu Ukládání člena do databáze Teddy Bears are Great (vytvořeno ve středu 25. května 2011 02:19:14 AM uživatelem fred) Ukládání tématu do databáze

Jak vidíte, rozhraní mohou propojovat třídy, které spolu pro určité účely nemají nic společného, ​​jako je zápis do databáze objektů tříd. Nezapomeňte, že jedna třída může implementovat několik rozhraní:

Třída MyClass implementuje rozhraní anInterface, otherInterface ( ... )

Poznámka: Rozhraní jsou výkonnou funkcí OOP a dá se o nich říci mnohem více. Více se o nich dozvíte v dokumentaci PHP.

Závěr

V této lekci jste se dozvěděli o jedné z nejmocnějších vlastností OOP – dědičnosti. Naučili jste se:

  1. Jak funguje dědičnost a jak ji používat k rozšíření tříd;
  2. Jak vytvořit dětské třídy v PHP;
  3. Proč byste mohli chtít přetěžovat metody v dětských třídách;
  4. Jak získat přístup k metodám supertřídy;
  5. Vše o konečných metodách a třídách a proč je užitečné je používat;
  6. Koncept abstraktních tříd pro vytváření šablon podřízených tříd;
  7. Jak používat rozhraní k poskytování společných funkcí nesouvisejícím třídám.

Pokud jste dokončili všechny lekce v této sérii, pak již budete schopni psát složité aplikace v OOP. Gratuluji!

V dalším a posledním tutoriálu vám ukážu některé super užitečné funkce OOP, které PHP má.

Do té doby šťastné kódování!

Při práci s třídami v PHP musíte často rozšířit funkčnost kódu. Pokud však není možné původní třídu změnit, lze ji snadno rozšířit vytvořením „kopie“.

Třídy, které rozšiřují originál, se nazývají " dceřiné společnosti"a rodič je" supertřída Supertřída může mít mnoho dětských tříd.

rozšiřuje

Podívejme se na základní principy třídní dědičnosti:

  • Pomocí dědičnosti můžeme vytvořit třídy, které budou obsahovat všechny vlastnosti a metody rodičovské třídy, tzn. dětské třídy dědí veřejnost A chráněný vlastnosti a metody nadřazené třídy.
  • Podřízená třída je rozšířením nadřazené třídy, protože kromě zděděných vlastností a metod může obsahovat i své vlastní.
  • Dědičnost se zakládá použitím slova rozšiřuje při vytváření třídy.
  • Pokud dědic nemá svůj vlastní konstruktor (psal jsem o tom dříve), automaticky se spustí rodičovský konstruktor. Pokud má podřízená třída konstruktor, nadřazený konstruktor se nespustí.
  • Podřízené třídy mohou přepsat vlastnosti a metody nadtřídy. Definováním podtřídy zajistíme, že její instance je definována charakteristikami nejprve podřízené a poté nadřazené třídy.

Podívejme se na jednoduchý příklad. Ať máme třídu Ploshad, který vypočítá plochu povrchu. Nyní jsme ale potřebovali spočítat jeho objem. Původní třídu nelze změnit. Vytvořme podřízenou třídu Obyem, který zdědí všechny vlastnosti a metody Ploshad a přidejte funkci pro výpočet objemu:

třída čtverec (
chráněná $šířka;
chráněná $výška;
veřejná funkce __construct($x, $y) (
$this->width = $x;
$this->height = $y; )
veřejná funkce Square() ( return $this->width * $this->height; )
}

třída Obyem rozšiřuje Ploshad (
chráněný $glybina;
veřejná funkce Obyemss($g) (
$this->glybina = $g;
return $this->Square()* $this->glybina;
}
}

Nahrávkou třída Obyem rozšiřuje Ploshad deklarovali jsme, že třída Obyem dědí vlastnosti a metody třídy Ploshad a umí je ovládat. Uvnitř Obyem zaregistrovali jsme novou nemovitost $glybina a způsob veřejná funkce Obyemss($g). Nyní spočítejme objem a plochu:

$obj = new Obyem(2,12); //vytvoří předmět od dědice
echo "Oblast: ".$obj->Square(); //stará rodičovská funkce
echo "Volume: ".$obj->Obyemss(2); //nová funkce dědice

Jak můžete vidět z komentářů, $obj nyní může používat jak staré metody třídy Ploshad, tak nové metody podřízené třídy Obyem.

Při výpočtu oblasti hledá interpret PHP konstruktor ve třídě Obyem, pokud není nalezen, spustí konstruktor v Ploshadu. Přepíše hodnoty předávaných vlastností (Obyem(2,12)). Metoda Square() se poté spustí a použije tato data.

V případě volume se spouští i konstruktor v Ploshadu a následně metoda Obyemss($g), ve které se předává výška. Uvnitř metody použijeme výpočet plochy vynásobené výškou a dostaneme výsledek.

Dědičnost se používá, když je funkce v rámci jedné třídy příliš složitá na pochopení a práci s ní, stejně jako na vytváření výjimek nebo rozlišování mezi datovými typy. Máte například třídu pro vykládání knižních produktů s mnoha obory (autor, rok vydání, počet stran). Nyní, pokud jste potřebovali zobrazit produkt s jiným typem, například: DVD hry, pak bude mít jiné parametry (systémové požadavky). Pokud se tedy třída začne podobat dvěma třídám, je lepší provést dědičnost.

PHP interpret se vždy nejprve podívá na podřízenou třídu:

  1. Existuje konstruktér? Pokud existuje, ignoruje konstruktor rodiče
  2. Existují vlastnosti a metody? Pokud se shodují v dítěti a rodiči, pak jsou použity děti. Můžete tak zcela přepsat funkčnost metod nadřazené třídy.

rozšiřuje rodič::

rodič::- používá se, pokud je třeba změnit funkčnost nadřazené metody v podřízené třídě

Příklad:
třída PloshadProcent rozšiřuje Ploshad (
funkce Square() (
$str = parent::Square();
$str = $str*0,1;
return $str;
}
}

Nyní, když zavoláme, obdržíme 10% naší oblasti:
$obj2 = new PloshadProcent(2,12);
echo "Plocha 10%: ".$obj2->Square(); //dá 2.4

Přepsali jsme metodu nadtřídy Square() uvnitř PloshadProcent

Druhý a velmi důležitý způsob, jak použít parent::, je přepsat funkčnost konstruktoru uvnitř podřízené třídy. To lze použít, pokud nadtřída nemá žádné nové vlastnosti, se kterými by bylo možné pracovat:

Nechť existuje třída kniha a její konstruktor má pouze 2 parametry: $title, $price.

třídní kniha (
veřejný $titul;
veřejná cena $;
funkce __construct($title, $price) (
$this->title = $title;
$tato->cena = $cena;
}
}

Najednou jsme potřebovali zobrazit nový parametr $pages. Vytvoříme instanci třídy new_book a uděláme si v ní vlastní konstruktor, který již bude obsahovat potřebná data: $title, $price, $pages

Když podřízená třída definuje svůj vlastní konstruktor, PHP automaticky nevolá konstruktor nadřazené třídy. To je nutné provést ručně v konstruktoru podtřídy.

Podřízená třída ve svém konstruktoru zavolá konstruktor své nadřazené třídy, předá potřebné argumenty pro inicializaci, provede ji a poté se provede kód, který implementuje další funkce, v tomto případě inicializuje vlastnost podtřídy.

třída nová_kniha rozšiřuje knihu (
veřejné $stránky;
function __construct($title, $price, $pages) (
parent::__construct($title, $cena); // volání metody konstruktoru nadřazené třídy
$this->pages = $pages; // inicializuje vlastnost definovanou v podtřídě
}
}
$obj = nová nová_kniha("ABC", 35, 500);
echo "Kniha: $obj->title | Cena: $obj->price | Stránky: $obj->pages";

Tímto způsobem můžeme rozšířit funkčnost nadtříd, aniž bychom je měnili samy. V další lekci se to naučíte




Nahoru