Tur belgilash — parametr va qaytish turlari, strict_types

~15 daq · PHP · Funksiyalar

Muammodan boshlaylik

Hamkasbingiz yozgan funksiya:

<?php

function chegirma($narx, $foiz)
{
    return $narx * $foiz / 100;
}

Savollar: $foiz — 15 mi yoki 0.15 mi? $narx — son mi yoki "250 000 so'm" degan matn ham bo'lishi mumkinmi? Funksiya nima qaytaradi? Javob bilish uchun kodni o'qib chiqish yoki muallifdan so'rash kerak.

Endi tasavvur qiling, kimdir chegirma("bepul", 10) deb chaqirdi. PHP 8 da bu TypeError — lekin xato funksiya ichida chiqadi va qayerdan noto'g'ri qiymat kelganini topish qiyin.

Tur belgilash (type declarations) ikkala muammoni hal qiladi: kod o'zini o'zi hujjatlaydi va xato kirish eshigida ushlanadi.


Parametr turlari

<?php

function chegirma(int $narx, int $foiz)
{
    return $narx * $foiz / 100;
}

echo chegirma(200000, 15);   // 30000

Endi funksiya e'lonining o'zi aytib turibdi: ikkala parametr — butun son.

Noto'g'ri tur berilsa:

<?php

echo chegirma("bepul", 10);
// TypeError: chegirma(): Argument #1 ($narx) must be of type int, string given

Xato aniq: qaysi funksiya, qaysi parametr, nima kutilgan, nima kelgan.


Qaytish turi

Qavsdan keyin : va tur:

<?php

function chegirma(int $narx, int $foiz): float
{
    return $narx * $foiz / 100;
}

function toliqIsm(string $ism, string $familiya): string
{
    return "$ism $familiya";
}

function kattami(int $yosh): bool
{
    return $yosh >= 18;
}

Hech narsa qaytarmaydigan funksiya — void:

<?php

function logYoz(string $xabar): void
{
    file_put_contents('app.log', $xabar . PHP_EOL, FILE_APPEND);
    // return yo'q yoki faqat `return;`
}

Mavjud turlar

Tur Ma'nosi
int, float, string, bool Oddiy turlar
array Massiv
void Hech narsa qaytarmaydi (faqat qaytish turi)
null Faqat null
mixed Istalgan tur
callable Chaqirib bo'ladigan narsa (funksiya)
?int int yoki null
int|string int yoki string (union)
never Hech qachon qaytmaydi (doim xato tashlaydi yoki exit)
ClassNomi Shu class ob'ekti (OOP qismida)

Nullable: ?

"Qiymat bo'lishi ham, bo'lmasligi ham mumkin":

<?php

function foydalanuvchiniTop(int $id): ?array
{
    $baza = [1 => ["ism" => "Ali"], 2 => ["ism" => "Vali"]];
    return $baza[$id] ?? null;   // topilmasa — null
}

$user = foydalanuvchiniTop(5);
if ($user === null) {
    echo "Topilmadi";
}

?array — "massiv yoki null qaytaraman, null ni tekshiring" degan ogohlantirish.

Union: |

<?php

function idniTozala(int|string $id): int
{
    return (int) $id;
}

Avtomatik moslashtirish va strict_types

Bir narsa sizni hayratda qoldirishi mumkin:

<?php

function ikkiBaravar(int $son): int
{
    return $son * 2;
}

echo ikkiBaravar("21");   // 42 — xato yo'q!

"21" — string, lekin PHP uni jimgina int ga aylantirdi. Bu default (yumshoq) rejim: agar qiymatni xatosiz aylantirish mumkin bo'lsa — PHP aylantiradi.

Qat'iy rejimni yoqish uchun faylning eng birinchi qatoriga:

<?php

declare(strict_types=1);

function ikkiBaravar(int $son): int
{
    return $son * 2;
}

echo ikkiBaravar("21");
// TypeError: ikkiBaravar(): Argument #1 ($son) must be of type int, string given

Endi PHP hech narsani taxmin qilmaydi. Turlar mos kelmasa — xato.

[!TIP] Zamonaviy PHP loyihalarda (Laravel, Symfony paketlari) deyarli har bir fayl declare(strict_types=1); bilan boshlanadi. Siz ham shunga odatlaning. Faqat esda tuting: formadan kelgan qiymatlar doim string — ularni funksiyaga berishdan oldin o'zingiz (int) bilan aylantirasiz.

Bitta istisno: strict_types da ham int ni float parametrga berish mumkin — bu ma'lumot yo'qotmaydi.


Nima uchun shunday?

Nima uchun PHP turlarni majburiy qilmaydi, strict_types ni ham o'chiq holda qoldiradi?

PHP 20 yildan ortiq turlarsiz yashagan va internetda milliardlab qator shunday kod bor. Turlar majburiy bo'lsa — hammasi bir kunda buzilardi. Shuning uchun tur belgilash ixtiyoriy qo'shilgan (PHP 7.0, 2015), strict_types esa har bir fayl uchun alohida yoqiladi. Bu eski kodni buzmasdan yangi kodni xavfsiz yozish imkonini beradi.


Hujjatlash: DocBlock

Ba'zan tur yetarli emas — masalan, array ichida nima borligi. Buning uchun izoh:

<?php

/**
 * Mahsulotlarning umumiy narxini hisoblaydi.
 *
 * @param array<int, array{nom: string, narx: int, soni: int}> $mahsulotlar
 * @return int Jami summa, so'mda
 */
function jamiNarx(array $mahsulotlar): int
{
    $jami = 0;
    foreach ($mahsulotlar as $m) {
        $jami += $m['narx'] * $m['soni'];
    }
    return $jami;
}

PHP bu izohni tekshirmaydi, lekin muharrir (PHP Intelephense) va tahlil vositalari (PHPStan) o'qiydi va xatolarni oldindan ko'rsatadi.


Tez-tez uchraydigan xatolar

declare birinchi qatorda emas:

<?php

echo "salom";
declare(strict_types=1);
// Fatal error: strict_types declaration must be the very first statement in the script

void funksiyadan qiymat qaytarish:

<?php

function a(): void
{
    return 5;
}
// Fatal error: A void function must not return a value

Qaytish turiga mos kelmaydigan qiymat:

<?php

declare(strict_types=1);

function ortacha(array $sonlar): int
{
    return array_sum($sonlar) / count($sonlar);   // 2.5 bo'lishi mumkin
}

echo ortacha([2, 3]);
// TypeError: ortacha(): Return value must be of type int, float returned

Yechim: qaytish turini float qiling yoki intdiv() / (int) ishlating.


Xulosa

Eslab qoling:

  • function nom(int $a, string $b): bool — parametr va qaytish turlari
  • ?tur — null ham bo'lishi mumkin; a|b — ikki turdan biri
  • void — hech narsa qaytarmaydi
  • Default holatda PHP mos keladigan qiymatni aylantiradi ("21" → 21)
  • declare(strict_types=1); — faylning birinchi qatorida, qat'iy rejim
  • Turlar — o'zini o'zi hujjatlaydigan kod va xatoni erta ushlash

Keyingi dars

16-dars: Scope, anonim funksiyalar va arrow function (fn)