Interface va abstract class
Muammodan boshlaylik
Do'koningiz to'lovlarni Payme orqali qabul qiladi. Kod hamma joyda PaymeTolov classini ishlatadi. Bir kuni buyurtmachi: "Click ni ham qo'shing, keyinroq Uzum ni ham".
PaymeTolov ishlatilgan 15 ta joyga if ($tizim === 'click') ... elseif ... qo'shasizmi? Har yangi tizimda yana 15 joyni o'zgartirasizmi?
Kerakli narsa — kelishuv: "to'lov tizimi qanday bo'lishidan qat'i nazar, unda tolash() va qaytarish() metodlari bo'ladi". Kod esa aniq tizimni emas, shu kelishuvni biladi. PHP da bunday kelishuv — interface.
Interface — kelishuv (shartnoma)
Interface faqat qanday metodlar bo'lishi kerakligini aytadi — ular qanday ishlashini emas:
<?php
interface TolovTizimi
{
public function tolash(int $summa, string $buyurtmaId): string; // tranzaksiya ID qaytaradi
public function qaytarish(string $tranzaksiyaId): bool;
}
Classlar bu kelishuvni amalga oshiradi (implements):
<?php
class PaymeTolov implements TolovTizimi
{
public function tolash(int $summa, string $buyurtmaId): string
{
// Payme API ga so'rov...
return 'payme_' . bin2hex(random_bytes(8));
}
public function qaytarish(string $tranzaksiyaId): bool
{
// Payme API ga so'rov...
return true;
}
}
class ClickTolov implements TolovTizimi
{
public function tolash(int $summa, string $buyurtmaId): string
{
// Click API ga so'rov — butunlay boshqacha ishlaydi
return 'click_' . bin2hex(random_bytes(8));
}
public function qaytarish(string $tranzaksiyaId): bool
{
return true;
}
}
Agar class interface dagi biror metodni yozmasa — PHP xato beradi:
Fatal error: Class ClickTolov contains 1 abstract method and must therefore be declared abstract
or implement the remaining methods (TolovTizimi::qaytarish)
Kelishuvni buzib bo'lmaydi.
Interface ning foydasi
Endi buyurtma kodi aniq tizimni bilmaydi:
<?php
class BuyurtmaXizmati
{
public function __construct(private TolovTizimi $tolov) {}
public function rasmiylashtirish(string $buyurtmaId, int $summa): string
{
$tranzaksiya = $this->tolov->tolash($summa, $buyurtmaId);
// buyurtmani bazaga saqlash...
return $tranzaksiya;
}
}
// Qaysi tizim ishlatilishini bitta joyda hal qilamiz
$tolov = match ($_POST['tolov_turi'] ?? 'payme') {
'click' => new ClickTolov(),
default => new PaymeTolov(),
};
$xizmat = new BuyurtmaXizmati($tolov);
$xizmat->rasmiylashtirish('B-1043', 315000);
Uzum qo'shish kerak bo'lsa:
UzumTolov implements TolovTizimiclassini yozasizmatchga bitta qator qo'shasiz
BuyurtmaXizmati — o'zgarmaydi. Bu OOP ning eng muhim tamoyillaridan biri: kod kengaytirish uchun ochiq, o'zgartirish uchun yopiq.
Test yozishda
<?php
class SoxtaTolov implements TolovTizimi
{
public function tolash(int $summa, string $buyurtmaId): string { return 'test_123'; }
public function qaytarish(string $tranzaksiyaId): bool { return true; }
}
$xizmat = new BuyurtmaXizmati(new SoxtaTolov()); // haqiqiy pul yechilmaydi
Bir nechta interface
Class faqat bitta otadan meros oladi, lekin istalgancha interface ni amalga oshira oladi:
<?php
interface JsongaAylanadi
{
public function toArray(): array;
}
interface Yetkaziladi
{
public function ogirlik(): float;
}
class Kitob implements JsongaAylanadi, Yetkaziladi
{
public function __construct(private string $nom, private float $kg) {}
public function toArray(): array { return ['nom' => $this->nom]; }
public function ogirlik(): float { return $this->kg; }
}
PHP ning o'zida ham tayyor interface lar bor: Countable (count($obj) ishlashi uchun), JsonSerializable (json_encode($obj) uchun), Stringable, IteratorAggregate (foreach uchun).
<?php
class Savat implements Countable
{
private array $qatorlar = [];
public function count(): int
{
return count($this->qatorlar);
}
}
echo count(new Savat()); // 0 — oddiy count() ishlaydi
Abstract class — yarim tayyor class
Ba'zan classlar faqat kelishuvni emas, umumiy kodni ham bo'lishadi. Interface kod saqlay olmaydi. Abstract class — saqlay oladi:
<?php
abstract class Bildirishnoma
{
public function __construct(protected string $qabulQiluvchi) {}
// Har bir bola o'zi yozishi SHART
abstract protected function yuborish(string $matn): bool;
// Umumiy mantiq — hamma bolalar uchun bir xil
public function jonat(string $matn): bool
{
if (trim($matn) === '') {
throw new InvalidArgumentException("Bo'sh xabar");
}
$natija = $this->yuborish($matn);
error_log(static::class . " → {$this->qabulQiluvchi}: " . ($natija ? 'OK' : 'XATO'));
return $natija;
}
}
class SmsBildirishnoma extends Bildirishnoma
{
protected function yuborish(string $matn): bool
{
// SMS shlyuzi API...
return true;
}
}
class TelegramBildirishnoma extends Bildirishnoma
{
protected function yuborish(string $matn): bool
{
// Telegram Bot API...
return true;
}
}
$b = new TelegramBildirishnoma('@foydalanuvchi');
$b->jonat("Buyurtmangiz yo'lda");
abstract class— undan to'g'ridan-to'g'ri ob'ekt yaratib bo'lmaydi (new Bildirishnoma()— xato)abstract protected function yuborish()— tanasiz metod; bolalar uni yozishga majburjonat()— tayyor metod: tekshirish va loglash hamma uchun bir xil
Bu naqsh Template Method deyiladi: umumiy algoritm otada, o'zgaruvchan qadam bolalarda.
Interface yoki abstract class?
| Interface | Abstract class | |
|---|---|---|
| Kod saqlaydimi | Yo'q (faqat metod imzolari) | Ha |
| Xususiyatlar | Yo'q (faqat konstantalar) | Ha |
| Nechta | Istalgancha implements |
Faqat bitta extends |
| Ma'nosi | "Nima qila oladi" | "Nima ekanligi" + umumiy kod |
Qoida:
- Avval interface dan boshlang — u eng moslashuvchan
- Bir nechta amalga oshirish bir xil kodni takrorlayotganini ko'rsangiz — umumiy qismni abstract class ga chiqaring
- Ko'pincha ikkalasi birga ishlatiladi:
abstract class AsosiyTolov implements TolovTizimi
Nima uchun shunday?
Nima uchun "aniq classga emas, interface ga bog'lan" degan qoida bunchalik muhim?
Tasavvur qiling: devordagi rozetka. U aniq bir dazmol yoki choynakni bilmaydi — u faqat "vilka standarti" ni biladi (interface). Shuning uchun istalgan qurilmani ulash mumkin va rozetkani o'zgartirish shart emas. Agar har bir qurilmaga alohida rozetka kerak bo'lganida — har yangi qurilmada devorni buzardingiz. Kodda ham shunday: interface — standart vilka, classlar — qurilmalar.
Xulosa
Eslab qoling:
interface— metodlar kelishuvi;implementsbilan amalga oshiriladi- Class bir nechta interface ni amalga oshira oladi
- Kodni aniq classga emas, interface ga bog'lang — almashtirish va test oson
abstract class— umumiy kod + bolalar majburiy yozadiganabstractmetodlarabstract classdannewqilib bo'lmaydi- Interface dan boshlang, takrorlanish paydo bo'lsa — abstract class
Keyingi dars
32-dars: static, trait, readonly va enum