Class va ob'ekt — xususiyat, metod, $this, konstruktor
Muammodan boshlaylik
Internet do'kondagi savatni massiv va funksiyalar bilan yozdik:
<?php
$savat = [];
function savatgaQosh(array &$savat, string $nom, int $narx, int $soni): void { /* ... */ }
function savatJami(array $savat): int { /* ... */ }
function savatTozala(array &$savat): void { /* ... */ }
Ishlaydi. Lekin muammolar bor:
- Har bir funksiyaga
$savatni qo'lda uzatish kerak - Kimdir
$savat[] = 'salom';deb yozib qo'yishi mumkin — hech narsa to'xtatmaydi savatJami()ni boshqa massiv bilan chaqirish mumkin — u nima ekanini bilmaydi- Ma'lumot va uni boshqaradigan funksiyalar alohida yashaydi
OOP (Ob'ektga yo'naltirilgan dasturlash) ma'lumot va uning ustidagi amallarni bitta birlikka birlashtiradi.
Class va ob'ekt
Class — chizma (loyiha). Ob'ekt — shu chizma bo'yicha yasalgan narsa.
Hayotiy o'xshatma: avtomobil zavodidagi chizma — bu class. Undan yasalgan har bir mashina — ob'ekt. Chizma bitta, mashinalar ko'p. Har bir mashinaning o'z rangi, o'z probegi bor, lekin hammasi bir xil tuzilgan va bir xil ishlaydi.
<?php
class Mahsulot
{
public string $nom;
public int $narx;
}
$telefon = new Mahsulot(); // ob'ekt yaratish
$telefon->nom = "Telefon";
$telefon->narx = 3200000;
$quloqchin = new Mahsulot();
$quloqchin->nom = "Quloqchin";
$quloqchin->narx = 249000;
echo $telefon->nom; // Telefon
echo $quloqchin->nom; // Quloqchin
class Mahsulot— class e'loni, nom PascalCase dapublic string $nom;— xususiyat (property): ob'ektning ma'lumotinew Mahsulot()— yangi ob'ekt yaratish->— ob'ektning xususiyati yoki metodiga murojaat
Metodlar — ob'ektning amallari
Metod — class ichidagi funksiya:
<?php
class Mahsulot
{
public string $nom;
public int $narx;
public function chegirmaliNarx(int $foiz): int
{
return $this->narx - intdiv($this->narx * $foiz, 100);
}
public function formatlanganNarx(): string
{
return number_format($this->narx, 0, '', ' ') . " so'm";
}
}
$telefon = new Mahsulot();
$telefon->nom = "Telefon";
$telefon->narx = 3200000;
echo $telefon->formatlanganNarx(); // 3 200 000 so'm
echo $telefon->chegirmaliNarx(10); // 2880000
$this nima?
$this — "men", ya'ni metod chaqirilgan ob'ektning o'zi.
$telefon->formatlanganNarx() chaqirilganda, metod ichidagi $this — bu $telefon. $quloqchin->formatlanganNarx() chaqirilganda — $quloqchin. Bitta metod — har bir ob'ekt uchun o'z ma'lumoti bilan ishlaydi.
Konstruktor — yaratilish paytida sozlash
Yuqoridagi misolda muammo bor:
<?php
$x = new Mahsulot();
echo $x->formatlanganNarx();
// Error: Typed property Mahsulot::$narx must not be accessed before initialization
Ob'ekt yaratildi, lekin ichi bo'sh. Konstruktor buni hal qiladi — u new chaqirilganda avtomatik ishga tushadi:
<?php
class Mahsulot
{
public string $nom;
public int $narx;
public function __construct(string $nom, int $narx)
{
if ($narx < 0) {
throw new InvalidArgumentException("Narx manfiy bo'lishi mumkin emas");
}
$this->nom = $nom;
$this->narx = $narx;
}
public function formatlanganNarx(): string
{
return number_format($this->narx, 0, '', ' ') . " so'm";
}
}
$telefon = new Mahsulot("Telefon", 3200000);
echo $telefon->formatlanganNarx(); // 3 200 000 so'm
new Mahsulot("Xato", -100); // InvalidArgumentException
Endi Mahsulot ob'ekti hech qachon yarim tayyor yoki noto'g'ri holatda bo'lmaydi. Bu — OOP ning asosiy foydasi.
__construct — ikki past chiziq bilan boshlanadigan "sehrli metod". PHP ularni maxsus holatlarda o'zi chaqiradi.
Muammoni hal qilamiz: Savat classi
<?php
declare(strict_types=1);
class Mahsulot
{
public function __construct(
public string $nom,
public int $narx,
) {}
}
class Savat
{
private array $qatorlar = [];
public function qosh(Mahsulot $mahsulot, int $soni = 1): void
{
if ($soni < 1) {
throw new InvalidArgumentException("Soni kamida 1");
}
$this->qatorlar[] = ['mahsulot' => $mahsulot, 'soni' => $soni];
}
public function jami(): int
{
$jami = 0;
foreach ($this->qatorlar as $q) {
$jami += $q['mahsulot']->narx * $q['soni'];
}
return $jami;
}
public function soni(): int
{
return count($this->qatorlar);
}
public function tozala(): void
{
$this->qatorlar = [];
}
}
$savat = new Savat();
$savat->qosh(new Mahsulot("Kitob", 85000), 3);
$savat->qosh(new Mahsulot("Daftar", 12000), 5);
echo $savat->soni(); // 2
echo $savat->jami(); // 315000
Yangi narsalar:
public function __construct(public string $nom, ...)— constructor promotion: xususiyatni e'lon qilish va qiymat berish bitta qatorda (keyingi darsda batafsil)private array $qatorlar— tashqaridan kirib bo'lmaydi.$savat->qatorlar[] = 'salom'— xato beradi. Savatni faqatqosh()orqali o'zgartirish mumkin, u esa tekshiradi.qosh(Mahsulot $mahsulot)— parametr turi class. Unga faqatMahsulotob'ekti berish mumkin.
Endi muammodagi to'rtta kamchilik ham hal bo'ldi.
Ob'ektlar havola orqali uzatiladi
Massivlar funksiyaga nusxa sifatida beriladi. Ob'ektlar esa — havola (bir xil ob'ektga ishora):
<?php
function narxniOshir(Mahsulot $m): void
{
$m->narx += 10000;
}
$kitob = new Mahsulot("Kitob", 85000);
narxniOshir($kitob);
echo $kitob->narx; // 95000 — asl ob'ekt o'zgardi!
$nusxa = $kitob; // bu NUSXA EMAS — o'sha ob'ektning ikkinchi nomi
$nusxa->narx = 1;
echo $kitob->narx; // 1
$haqiqiyNusxa = clone $kitob; // haqiqiy nusxa
Massivlarda & kerak edi — ob'ektlarda bu o'z-o'zidan shunday.
Ob'ektni tekshirish
<?php
$x = new Mahsulot("Kitob", 85000);
var_dump($x instanceof Mahsulot); // bool(true)
echo $x::class; // Mahsulot
var_dump($x);
// object(Mahsulot)#1 (2) { ["nom"]=> string(5) "Kitob" ["narx"]=> int(85000) }
Nima uchun shunday?
Nima uchun OOP kerak, agar funksiyalar bilan ham hammasini yozsa bo'lsa?
Kichik skriptda — haqiqatan ham kerak emas. Lekin loyiha o'sib, 50 ming qatorga va 5 ta dasturchiga yetganda asosiy savol tug'iladi: "Bu ma'lumotni kim o'zgartirishi mumkin?". Massiv bo'lsa — hamma, istalgan joyda. Ob'ekt bo'lsa — faqat uning metodlari, va ular qoidalarni tekshiradi. OOP — katta kodni boshqariladigan qismlarga bo'lish va har bir qismning ichki tuzilmasini himoya qilish usuli. Laravel, Symfony, WordPress plaginlari — hammasi classlar ustiga qurilgan.
Tez-tez uchraydigan xatolar
$this siz murojaat:
public function jami(): int
{
return $narx * 2; // ❌ Undefined variable $narx
return $this->narx * 2; // ✅
}
-> dan keyin $ qo'yish:
echo $telefon->$nom; // ❌ bu "o'zgaruvchi nomli xususiyat" degani
echo $telefon->nom; // ✅
Classni ikki marta e'lon qilish — Cannot declare class Mahsulot, because the name is already in use. Class fayllarini require_once bilan ulang (33-darsda autoload bilan butunlay hal qilamiz).
Xulosa
Eslab qoling:
- Class — chizma, ob'ekt —
newbilan yaratilgan nusxa - Xususiyat — ma'lumot, metod — amal;
->bilan murojaat $this— joriy ob'ekt__construct— yaratilishda avtomatik chaqiriladi; ob'ektni to'g'ri holatda boshlaydiprivate— tashqaridan yopiq; o'zgartirish faqat metodlar orqali- Ob'ektlar havola orqali uzatiladi; nusxa uchun
clone
Keyingi dars
29-dars: public, private, protected va constructor promotion