static, trait, readonly va enum
Muammodan boshlaylik
Uchta alohida muammo:
- Narxni formatlash funksiyasi
Narxclassiga tegishli, lekin uni chaqirish uchun har safarnew Narx()yaratish kerakmi? Unda hech qanday ma'lumot yo'q-ku. Mahsulot,Maqola,Foydalanuvchiclasslarining hammasida bir xilyaratilgan_vaqtvayangilangan_vaqtmantig'i bor. Ular bir-biridan meros olmaydi. Kodni qanday bo'lishamiz?- Buyurtma holati
'new','paid','shipped'— oddiy string. Kimdir'payed'deb yozib qo'ydi — hech narsa xato bermadi, buyurtma "yo'qolib" qoldi.
Uchtasining ham PHP da tayyor yechimi bor.
static — ob'ektga emas, classga tegishli
<?php
class Narx
{
public static function format(int $summa): string
{
return number_format($summa, 0, '', ' ') . " so'm";
}
}
echo Narx::format(3200000); // 3 200 000 so'm — new kerak emas
staticmetod ob'ektsiz,Klass::metod()bilan chaqiriladi- Ichida
$thisyo'q — chunki ob'ekt yo'q
Static xususiyat — barcha ob'ektlar uchun bitta umumiy qiymat:
<?php
class Foydalanuvchi
{
private static int $soni = 0;
public function __construct(public string $ism)
{
self::$soni++;
}
public static function jamiSoni(): int
{
return self::$soni;
}
}
new Foydalanuvchi("Ali");
new Foydalanuvchi("Vali");
echo Foydalanuvchi::jamiSoni(); // 2
self:: — "shu class" (ichkaridan murojaat).
Named constructor — static ning eng foydali ishlatilishi
<?php
class Pul
{
private function __construct(private int $tiyin) {} // private konstruktor!
public static function somdan(int $som): self
{
return new self($som * 100);
}
public static function tiyindan(int $tiyin): self
{
return new self($tiyin);
}
public function som(): float
{
return $this->tiyin / 100;
}
}
$a = Pul::somdan(5000);
$b = Pul::tiyindan(250);
new Pul(5000) — 5000 so'mmi yoki tiyinmi? Noaniq. Pul::somdan(5000) — aniq. DateTimeImmutable::createFromFormat() ham aynan shunday.
[!WARNING] Static ni suiiste'mol qilmang. Hamma narsani
staticqilsangiz — bu shunchaki funksiyalar to'plami bo'lib qoladi, OOP ning foydalari (almashtirish, test, interface) yo'qoladi. Static — holatsiz yordamchilar va named constructor lar uchun.
Class konstantalari
<?php
class Buyurtma
{
public const MAKS_MAHSULOT = 50;
private const SOLIQ = 0.12;
public function soliq(int $summa): int
{
return (int) ($summa * self::SOLIQ);
}
}
echo Buyurtma::MAKS_MAHSULOT; // 50
Trait — kodni gorizontal bo'lishish
Trait — bir nechta classga "nusxalab qo'yiladigan" metodlar to'plami:
<?php
trait VaqtBelgilari
{
private ?DateTimeImmutable $yaratilgan = null;
private ?DateTimeImmutable $yangilangan = null;
public function yaratilganDebBelgila(): void
{
$this->yaratilgan = new DateTimeImmutable();
$this->yangilangan = $this->yaratilgan;
}
public function yangilanganDebBelgila(): void
{
$this->yangilangan = new DateTimeImmutable();
}
public function yaratilgan(): ?DateTimeImmutable
{
return $this->yaratilgan;
}
}
class Mahsulot
{
use VaqtBelgilari;
public function __construct(public string $nom) {}
}
class Maqola
{
use VaqtBelgilari;
public function __construct(public string $sarlavha) {}
}
$m = new Mahsulot("Telefon");
$m->yaratilganDebBelgila();
echo $m->yaratilgan()->format('d.m.Y');
use VaqtBelgilari; — PHP trait ichidagi hamma narsani shu classga ko'chirib qo'yadi. Meros emas — Mahsulot va Maqola bir-biri bilan bog'liq emas.
Bir nechta trait:
class Maqola
{
use VaqtBelgilari, SoftDelete, Sluggable;
}
Laravel da bu juda ko'p: use HasFactory, SoftDeletes, Notifiable;.
[!INFO] Trait — kuchli, lekin "yashirin" kod: classni o'qiyotganda metodlar qayerdan kelganini ko'rish uchun trait faylini ochish kerak. Haqiqatan ham ko'p bog'liq bo'lmagan classlarda takrorlanadigan kichik mantiq uchun ishlating.
Enum — cheklangan qiymatlar to'plami (PHP 8.1+)
Muammodagi buyurtma holatlari:
<?php
enum BuyurtmaHolati: string
{
case Yangi = 'new';
case Tolangan = 'paid';
case Yolda = 'shipped';
case Yetkazildi = 'delivered';
case Bekor = 'cancelled';
}
Endi holat — oddiy string emas, maxsus tur:
<?php
class Buyurtma
{
public function __construct(
public readonly int $id,
public BuyurtmaHolati $holat = BuyurtmaHolati::Yangi,
) {}
}
$b = new Buyurtma(1043);
$b->holat = BuyurtmaHolati::Tolangan; // ✅
$b->holat = 'payed'; // ❌ TypeError — xato yozish imkonsiz
Bazadan / formadan kelgan qiymatni o'girish
<?php
$holat = BuyurtmaHolati::from('paid'); // BuyurtmaHolati::Tolangan
$holat = BuyurtmaHolati::from('payed'); // ValueError — noto'g'ri qiymat
$holat = BuyurtmaHolati::tryFrom('payed'); // null — xato bermaydi
echo BuyurtmaHolati::Tolangan->value; // paid — bazaga yozish uchun
echo BuyurtmaHolati::Tolangan->name; // Tolangan
Enum ichida metodlar
<?php
enum BuyurtmaHolati: string
{
case Yangi = 'new';
case Tolangan = 'paid';
case Yolda = 'shipped';
case Yetkazildi = 'delivered';
case Bekor = 'cancelled';
public function matn(): string
{
return match ($this) {
self::Yangi => "Yangi",
self::Tolangan => "To'langan",
self::Yolda => "Yo'lda",
self::Yetkazildi => "Yetkazildi",
self::Bekor => "Bekor qilingan",
};
}
public function rang(): string
{
return match ($this) {
self::Yetkazildi => 'yashil',
self::Bekor => 'qizil',
default => 'kulrang',
};
}
public function bekorQilishMumkinmi(): bool
{
return in_array($this, [self::Yangi, self::Tolangan], true);
}
}
$h = BuyurtmaHolati::from('shipped');
echo $h->matn(); // Yo'lda
var_dump($h->bekorQilishMumkinmi()); // bool(false)
// Select uchun barcha variantlar
foreach (BuyurtmaHolati::cases() as $holat) {
echo "<option value='{$holat->value}'>{$holat->matn()}</option>";
}
match ichida default yozilmasa va yangi holat qo'shilsa — PHP UnhandledMatchError beradi. Biror joyni yangilashni unutmaysiz.
Nima uchun shunday?
Nima uchun enum kerak edi, agar class konstantalari (const YANGI = 'new') bilan ham shunday qilsa bo'lardi?
Konstanta — baribir oddiy string. function holatniOzgartir(string $holat) ga Buyurtma::YANGI ham, 'salom' ham berish mumkin — PHP farqlamaydi. Enum esa alohida tur: function holatniOzgartir(BuyurtmaHolati $holat) faqat beshta ruxsat etilgan qiymatdan birini qabul qiladi. Xato dastur ishga tushganda emas, kod yozilayotganda (muharrirda) ko'rinadi.
Xulosa
Eslab qoling:
static— ob'ektga emas, classga tegishli;Klass::metod(), ichida$thisyo'q- Named constructor:
Pul::somdan(5000)—newdan aniqroq const— class konstantasi,self::NOMtrait+use— bog'liq bo'lmagan classlar orasida kod bo'lishishenum— cheklangan qiymatlar uchun alohida tur;from,tryFrom,cases(),->value- Enum ichida metod yozish mumkin — matn, rang, qoidalar
Keyingi dars
33-dars: Namespace va autoload