2.4 Meros (inheritance)¶
β¬ οΈ Oldingi: 2.3 Kirish darajalari: public va private Β· π README Β· Keyingi: 2.5 Abstrakt class'lar β‘οΈ
Muammo: takrorlanuvchi class'lar¶
Tasavvur qiling, sizda ikkita class bor: It va Mushuk. Ikkalasida ham nom xususiyati va ovqatlan() metodi bor β bir xil. Faqat ovoz chiqarishi farq qiladi (it huradi, mushuk miyovlaydi). Bir xil kodni ikki marta yozish β yomon (xato topilsa, ikki joyni tuzatasiz).
Meros ana shuni hal qiladi: umumiy narsalarni bitta "ota class"ga yozasiz, qolgan class'lar undan meros olib, faqat o'ziga xos qismni qo'shadi.
Meros qanday ishlaydi¶
Bir nechta class uchun umumiy narsalarni ota class (parent) ga yozamiz. Boshqa class'lar undan extends so'zi bilan meros oladi:
<?php
// Ota class β umumiy narsalar
class Hayvon {
public $nom;
public function __construct($nom) {
$this->nom = $nom;
}
public function ovqatlan() {
echo $this->nom . " ovqatlanyapti";
}
}
// Bola class β Hayvondan meros oladi
class It extends Hayvon {
public function ovoz() {
echo $this->nom . ": Vov-vov!";
}
}
class Mushuk extends Hayvon {
public function ovoz() {
echo $this->nom . ": Miyov!";
}
}
$it = new It("Bobik");
$it->ovqatlan(); // Bobik ovqatlanyapti β Hayvondan meros olingan!
echo "<br>";
$it->ovoz(); // Bobik: Vov-vov! β It'ning o'ziniki
$mushuk = new Mushuk("Mosya");
$mushuk->ovqatlan(); // Mosya ovqatlanyapti β yana meros
$mushuk->ovoz(); // Mosya: Miyov!
Nima sodir bo'ldi:
- class It extends Hayvon β "It class'i Hayvon'dan meros oladi". extends β "kengaytiradi/meros oladi" degani.
- It o'zida nom va ovqatlan() ni yozmadi, lekin ularga ega β chunki Hayvondan meros oldi.
- It faqat o'ziga xos ovoz() metodini qo'shdi.
Demak: bola class ota class'dagi hamma narsaga ega bo'ladi, ustiga o'ziniki qo'shadi. Umumiy kod bir joyda (ota class'da) β takrorlanish yo'q.
Metodni qayta yozish (override)¶
Bola class ota class'dagi metodni "o'ziga moslab" qayta yozishi mumkin. Bu β override (qayta belgilash):
<?php
class Hayvon {
public $nom;
public function __construct($nom) {
$this->nom = $nom;
}
public function ovoz() {
echo $this->nom . ": (umumiy ovoz)";
}
}
class It extends Hayvon {
// Hayvon'dagi ovoz() ni o'zgartiramiz (override)
public function ovoz() {
echo $this->nom . ": Vov-vov!";
}
}
$it = new It("Bobik");
$it->ovoz(); // Bobik: Vov-vov! β bola class versiyasi ishladi
Bola class'da bir xil nomli metod yozsangiz, u ota class'nikini "ustini bosadi" β bola class obyektida bola versiyasi ishlaydi.
Quyidagi diagramma meros daraxtini ko'rsatadi: ota Hayvondagi $nom va ovqatlan() bolalarga meros bo'ladi, har bir bola esa ovoz() ni o'ziga moslab override qiladi:
parent:: β ota class'ga murojaat¶
Ba'zan bola class ota class'ning metodini chaqirib, ustiga o'ziniki qo'shmoqchi bo'ladi. Buning uchun parent:: ishlatiladi ("ota" degani):
<?php
class Hayvon {
public $nom;
public function __construct($nom) {
$this->nom = $nom;
}
}
class It extends Hayvon {
public $zot;
public function __construct($nom, $zot) {
parent::__construct($nom); // ota class konstruktorini chaqiramiz
$this->zot = $zot; // keyin o'zimiznikini qo'shamiz
}
}
$it = new It("Bobik", "Labrador");
echo $it->nom; // Bobik (ota class konstruktori to'ldirdi)
echo "<br>";
echo $it->zot; // Labrador (bola class konstruktori to'ldirdi)
parent::__construct($nom) β "ota class'ning konstruktorini ishga tushir va $nomni unga ber". Shunday qilib, ota class o'z ishini qiladi (nomni saqlaydi), bola class qolganini qo'shadi (zotni saqlaydi). Bu β takrorlamaslikning yaxshi usuli.
Nega meros foydali?¶
- Takrorlanmaslik: umumiy kod bir joyda.
- Tartib: o'xshash narsalar bir "oila"ga birlashtiriladi (
HayvonβIt,Mushuk). - Kengaytirish: yangi tur qo'shish oson β yangi bola class yozasiz, umumiy qismni qayta yozmaysiz.
Diqqat: merosni haddan tashqari ishlatmang. U faqat haqiqiy "...bu ham bir turdagi..." munosabati bo'lganda mantiqiy: "It β bu bir Hayvon", "Yuk mashinasi β bu bir Mashina". Agar shunday munosabat bo'lmasa, meros o'rniga boshqa usul (masalan, oddiy xususiyat) to'g'riroq bo'ladi.
Mashqlar¶
Oson
1. Hayvon (ota, nom bilan) va It (bola) class'larini yarating. It Hayvon'dan meros olsin.
2. Itga o'ziga xos ovoz() metodini qo'shing va ota class'dan kelgan ovqatlan() ni ham ishlating.
3. Mushuk class'ini ham Hayvondan meros qildiring.
4. Mashina (ota) va YukMashinasi (bola) class'larini yarating.
5. Foydalanuvchi (ota) va Admin (bola) class'larini yarating.
O'rta
6. Hayvondagi ovoz() ni Itda override qiling (it uchun "Vov-vov").
7. Shakl (ota, yuza() umumiy) β Kvadrat va Aylana (bolalar, har biri o'z yuza() siga ega) β override bilan.
8. Mashina (ota, konstruktor rang) β ElektrMashina (bola, qo'shimcha batareya). parent::__construct ishlating.
9. Xodim (ota, ism, maosh) β Menejer (bola, qo'shimcha bonus). parent::__construct bilan.
Qiyin
10. Hayvon ota class: nom, ovqatlan(), ovoz() (umumiy). It, Mushuk, Sigir bolalar β har biri ovoz() ni override qilsin. Hammasini yaratib, ovozlarini chiqaring.
11. Xodim (ota, maoshHisobla() umumiy maosh qaytaradi) β Menejer (bola, maoshHisobla() ni override qilib, maosh + bonus qaytaradi; parent::maoshHisobla() dan foydalaning).
12. Tolov (ota, summa, tasdiqla()) β NaqdTolov va KartaTolov (bolalar, har biri tasdiqla() ni o'ziga xos qilib override qiladi).
Yechim β 8 (parent::__construct)
<?php
class Mashina {
public $rang;
public function __construct($rang) {
$this->rang = $rang;
}
public function malumot() {
echo "Rang: " . $this->rang;
}
}
class ElektrMashina extends Mashina {
public $batareya;
public function __construct($rang, $batareya) {
parent::__construct($rang); // ota class rangni saqlaydi
$this->batareya = $batareya; // bola batareyani qo'shadi
}
public function malumot() {
parent::malumot(); // ota class malumotini chiqaradi
echo ", Batareya: " . $this->batareya . "%"; // ustiga qo'shadi
}
}
$e = new ElektrMashina("oq", 80);
$e->malumot(); // Rang: oq, Batareya: 80%
parent:: ni ikki joyda ishlatdik: konstruktorda (rangni saqlash) va malumotda (umumiy ma'lumotni chiqarish). Bola class faqat o'ziga xos qismni qo'shadi β qolgani ota class'da.
Yechim β 10 (Hayvon va bolalari)
<?php
class Hayvon {
public $nom;
public function __construct($nom) {
$this->nom = $nom;
}
public function ovqatlan() {
echo $this->nom . " ovqatlanyapti<br>";
}
public function ovoz() {
echo "..."; // umumiy (bolalar override qiladi)
}
}
class It extends Hayvon {
public function ovoz() { echo "Vov-vov"; }
}
class Mushuk extends Hayvon {
public function ovoz() { echo "Miyov"; }
}
class Sigir extends Hayvon {
public function ovoz() { echo "Mooo"; }
}
$hayvonlar = [new It("Bobik"), new Mushuk("Pishi"), new Sigir("Zumrad")];
foreach ($hayvonlar as $h) {
echo $h->nom . ": ";
$h->ovoz();
echo "<br>";
}
// Bobik: Vov-vov
// Pishi: Miyov
// Zumrad: Mooo
ovoz() ni o'zicha override qiladi (qayta yozadi). Bir massivda turli hayvonlarni saqlab, bittagina foreach bilan hammasini "gapirtirdik" β har biri o'z ovozini chiqaradi. Bu β polimorfizm: "bir buyruq, har xil natija".
Yechim β 11 (maosh + bonus)
<?php
class Xodim {
protected $maosh; // protected β pastda izoh
public function __construct($maosh) {
$this->maosh = $maosh;
}
public function maoshHisobla() {
return $this->maosh;
}
}
class Menejer extends Xodim {
private $bonus;
public function __construct($maosh, $bonus) {
parent::__construct($maosh);
$this->bonus = $bonus;
}
public function maoshHisobla() {
return parent::maoshHisobla() + $this->bonus; // asosiy maosh + bonus
}
}
$x = new Xodim(5000000);
echo $x->maoshHisobla(); // 5000000
$m = new Menejer(5000000, 2000000);
echo "<br>" . $m->maoshHisobla(); // 7000000
Yangi so'z:
protected. Bu βpublicvaprivateorasidagi uchinchi daraja.privatefaqat shu class ichida ishlaydi;protectedesa shu class va undan meros olgan bola class'lar ichida ishlaydi (lekin tashqaridan emas). Bu yerda$maoshniprotectedqildik, shundaMenejer(bola) unga murojaat qila olsin. Agarprivatebo'lsa, bola class undan foydalana olmasdi.
Yechim β 12 (Tolov turlari)
<?php
class Tolov {
protected $summa;
public function __construct($summa) {
$this->summa = $summa;
}
public function tasdiqla() {
echo "To'lov: " . $this->summa . " so'm";
}
}
class NaqdTolov extends Tolov {
public function tasdiqla() {
echo "Naqd: " . $this->summa . " so'm qabul qilindi";
}
}
class KartaTolov extends Tolov {
public function tasdiqla() {
echo "Karta: " . $this->summa . " so'm yechildi";
}
}
(new NaqdTolov(5000))->tasdiqla(); // Naqd: 5000 so'm qabul qilindi
echo "<br>";
(new KartaTolov(12000))->tasdiqla(); // Karta: 12000 so'm yechildi
Tolov summani saqlaydi va umumiy tasdiqla() beradi; har bir bola uni o'z usulida override qiladi. (Keyingi bo'limda β interfeys β bu g'oyani yanada qat'iyroq ko'rinishda ko'ramiz.)