public, private, protected va constructor promotion
Muammodan boshlaylik
Bank hisobi classi:
<?php
class Hisob
{
public int $balans = 0;
public function toldirish(int $summa): void
{
if ($summa <= 0) {
throw new InvalidArgumentException("Summa musbat bo'lsin");
}
$this->balans += $summa;
}
}
$hisob = new Hisob();
$hisob->balans = 999999999; // 😱
toldirish() metodida tekshiruv bor. Lekin balans — public, va har kim uni to'g'ridan-to'g'ri o'zgartira oladi. Tekshiruvning foydasi yo'q.
Ob'ektning ichki ma'lumotini himoya qilish — inkapsulyatsiya (encapsulation). Buning uchun kirish darajalari bor.
Uch daraja
| Daraja | Class ichida | Voris (meros) class da | Tashqarida |
|---|---|---|---|
public |
✅ | ✅ | ✅ |
protected |
✅ | ✅ | ❌ |
private |
✅ | ❌ | ❌ |
<?php
class Hisob
{
private int $balans = 0;
public function toldirish(int $summa): void
{
if ($summa <= 0) {
throw new InvalidArgumentException("Summa musbat bo'lsin");
}
$this->balans += $summa;
}
public function yechish(int $summa): void
{
if ($summa > $this->balans) {
throw new RuntimeException("Mablag' yetarli emas");
}
$this->balans -= $summa;
}
public function balans(): int
{
return $this->balans;
}
}
$hisob = new Hisob();
$hisob->toldirish(500000);
$hisob->yechish(120000);
echo $hisob->balans(); // 380000
$hisob->balans = 999999999;
// Error: Cannot modify private property Hisob::$balans
Endi balansni o'zgartirishning yagona yo'li — toldirish() va yechish(), ikkalasi ham qoidalarni tekshiradi. O'qish uchun esa alohida balans() metodi.
Hayotiy o'xshatma: bankomat. Siz ichidagi pul qutisiga to'g'ridan-to'g'ri qo'l tiqa olmaysiz. Faqat ekran va tugmalar (public metodlar) orqali — ular PIN kodni va balansni tekshiradi.
Qaysi darajani tanlash kerak?
Qoida: hamma narsani private qilib boshlang. Tashqaridan haqiqatan kerak bo'lgandagina public ga oching.
- Xususiyatlar — deyarli doim
private - Metodlar — tashqi dunyo uchun mo'ljallanganlari
public, ichki yordamchilarprivate protected— faqat meros orqali kengaytirish rejalashtirilgan bo'lsa (30-dars)
<?php
class Buyurtma
{
private array $qatorlar = [];
public function jami(): int // tashqi dunyo uchun
{
return $this->oraliqJami() - $this->chegirma();
}
private function oraliqJami(): int { /* ... */ return 0; } // ichki hisob
private function chegirma(): int { /* ... */ return 0; } // ichki hisob
}
private metodlarni keyinchalik bemalol o'zgartirasiz yoki o'chirasiz — tashqarida hech kim ularga bog'liq emas. public metodni o'zgartirish esa uni ishlatgan barcha kodni buzishi mumkin.
Constructor promotion (PHP 8.0+)
Klassik usul — juda ko'p takrorlanish:
<?php
class Foydalanuvchi
{
private string $ism;
private string $email;
private int $yosh;
public function __construct(string $ism, string $email, int $yosh)
{
$this->ism = $ism;
$this->email = $email;
$this->yosh = $yosh;
}
}
Har bir xususiyat nomi to'rt marta yozilgan. Constructor promotion bilan:
<?php
class Foydalanuvchi
{
public function __construct(
private string $ism,
private string $email,
private int $yosh = 18,
) {}
}
Natija aynan bir xil. Konstruktor parametriga kirish darajasi (private, public, protected) qo'yilsa — PHP avtomatik xususiyat yaratadi va qiymat beradi.
Tekshiruv kerak bo'lsa — konstruktor tanasiga yoziladi:
<?php
class Foydalanuvchi
{
public function __construct(
private string $ism,
private string $email,
) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException("Email noto'g'ri: $email");
}
}
public function ism(): string
{
return $this->ism;
}
}
readonly — faqat bir marta yoziladigan xususiyat (PHP 8.1+)
Ba'zi qiymatlar yaratilgandan keyin hech qachon o'zgarmasligi kerak — masalan, ID yoki yaratilgan sana.
<?php
class Buyurtma
{
public function __construct(
public readonly int $id,
public readonly DateTimeImmutable $yaratilgan,
) {}
}
$b = new Buyurtma(1043, new DateTimeImmutable());
echo $b->id; // 1043 — o'qish mumkin
$b->id = 5;
// Error: Cannot modify readonly property Buyurtma::$id
public readonly — "hamma o'qiy oladi, hech kim o'zgartira olmaydi". Bu getter metod yozmasdan himoya qilishning qisqa yo'li.
PHP 8.2 dan butun classni readonly qilish mumkin:
<?php
readonly class Pul
{
public function __construct(
public int $miqdor,
public string $valyuta,
) {}
}
Getter va setter
Boshqa tillardan kelgan odat — har bir xususiyat uchun getX() va setX():
<?php
class Mahsulot
{
private int $narx;
public function getNarx(): int { return $this->narx; }
public function setNarx(int $narx): void { $this->narx = $narx; }
}
Bu public int $narx dan farqi yo'q — himoya nol. Setter faqat tekshiruv yoki mantiq qo'shganda ma'noga ega. Yaxshiroq — metodni ma'noli nomlash:
<?php
class Mahsulot
{
public function __construct(private int $narx) {}
public function narx(): int
{
return $this->narx;
}
public function chegirmaQollash(int $foiz): void
{
if ($foiz < 0 || $foiz > 90) {
throw new InvalidArgumentException("Chegirma 0-90% oralig'ida");
}
$this->narx = intdiv($this->narx * (100 - $foiz), 100);
}
}
setNarx(5) — "narxni 5 qil". chegirmaQollash(10) — "10% chegirma qo'lla" — biznes ma'nosi aniq va qoidalar ichida.
Nima uchun shunday?
Nima uchun ma'lumotni yashirish kerak — biz o'zimiz yozgan kodga o'zimiz ishonmaymizmi?
Gap ishonchda emas, o'zgarishga tayyorlikda. Bugun $balans — oddiy son. Ertaga uni tiyinlarda saqlashga yoki har bir o'zgarishni logga yozishga qaror qildingiz. Agar $balans private bo'lsa — faqat class ichini o'zgartirasiz. Agar public bo'lsa va loyihaning 40 joyida $hisob->balans = ... yozilgan bo'lsa — 40 joyni qidirib topasiz. Inkapsulyatsiya — kelajakdagi o'zingizga g'amxo'rlik.
Xulosa
Eslab qoling:
public— hamma,protected— class va vorislari,private— faqat class ichi- Xususiyatlarni
privateqiling; o'zgartirish — tekshiruvli metodlar orqali - Constructor promotion:
public function __construct(private string $ism) {} readonly— bir marta beriladi, keyin faqat o'qiladi- Ma'nosiz getter/setter emas — ma'noli metodlar yozing
Keyingi dars
30-dars: Meros — extends, parent::, metodni qayta yozish