3-bo‘lim

Turlar va o'zgaruvchilar

PHP ning sakkiz turi, qat'iy turlar rejimi, taqqoslashdagi tuzoqlar va null bilan xavfsiz ishlash.

🕑 12 daqiqa o‘qish 📄 999 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Sakkiz tur
  2. Qat'iy turlar rejimi
  3. Taqqoslashdagi tuzoq
  4. null bilan xavfsiz ishlash
  5. Turga oshkora aylantirish
  6. Doimiylar
  7. Xulosa

PHP dinamik turli til: o'zgaruvchi turini oldindan e'lon qilmaysiz. Lekin bu "turlar yo'q" degani emas - turlar bor va ular bilan noto'g'ri ishlash eng ko'p uchraydigan xatolar manbai.

Sakkiz tur #

PHP
// Har bir misol qat'iy turlar rejimida ishlaydi.
PHP
$butun    = 42;
$kasr     = 3.14;
$satr     = "salom";
$mantiqiy = true;
$massiv   = [1, 2, 3];
$hech     = null;

foreach ([$butun, $kasr, $satr, $mantiqiy, $massiv, $hech] as $qiymat) {
    printf("%-10s %s\n", get_debug_type($qiymat), var_export($qiymat, true));
}

echo "\n";
echo "Obyekt turi:\n";
$obyekt = new stdClass();
$obyekt->nom = "Husanboy";
printf("%-10s %s\n", get_debug_type($obyekt), json_encode($obyekt));
Natija
int        42
float      3.14
string     'salom'
bool       true
array      array (
  0 => 1,
  1 => 2,
  2 => 3,
)
null       NULL

Obyekt turi:
stdClass   {"nom":"Husanboy"}
get_debug_type() va gettype() farqi

PHP 8 da get_debug_type() qo'shildi va u eski gettype() dan yaxshiroq:

Qiymatgettype()get_debug_type()
42integerint
3.14doublefloat
truebooleanbool
new Foo()objectFoo
nullNULLnull

Farqlar muhim: gettype() float ni double deb ataydi (bu C tilidan qolgan meros) va obyektning sinf nomini aytmaydi.

Yangi kodda har doim get_debug_type() ni ishlating - u turlarni xuddi kodda yozganingizdek nomlaydi.

Qat'iy turlar rejimi #

PHP
function kvadrat(int $son): int
{
    return $son * $son;
}

echo "To'g'ri chaqiruv: " . kvadrat(7) . "\n";

// Qat'iy rejimda satr avtomatik songa AYLANMAYDI
try {
    echo kvadrat("7");
} catch (TypeError $x) {
    echo "TypeError tutildi\n";
    echo "  xabar boshlanishi: " . rtrim(substr($x->getMessage(), 0, 46)) . "\n";
}

echo "\n";
echo "Aylantirish kerak bo'lsa - OSHKORA qiling:\n";
$kiritilgan = "7";
echo "  kvadrat((int) \$kiritilgan) = " . kvadrat((int) $kiritilgan) . "\n";
Natija
To'g'ri chaqiruv: 49
TypeError tutildi
  xabar boshlanishi: kvadrat(): Argument #1 ($son) must be of type

Aylantirish kerak bo'lsa - OSHKORA qiling:
  kvadrat((int) $kiritilgan) = 49
declare(strict_types=1) siz nima bo'ladi

Bu qatorsiz PHP yuqoridagi chaqiruvni jimgina qabul qiladi va "7" ni 7 ga aylantiradi. Qulay ko'rinadi - lekin quyidagi holatlarni ham qabul qiladi:

ChaqiruvQat'iy rejimsizQat'iy rejimda
kvadrat("7")49TypeError
kvadrat(7.9)49 (kasr yo'qoladi!)TypeError
kvadrat(true)1TypeError
kvadrat("7abc")49 + ogohlantirishTypeError

Ikkinchi qator eng xavflisi: 7.9 jimgina 7 ga aylanadi va hisobingiz noto'g'ri chiqadi. Hech qanday xato xabari bo'lmaydi.

Shuning uchun har bir faylning boshiga declare(strict_types=1); yozing. U faqat o'sha faylga ta'sir qiladi, shuning uchun uni hamma joyda takrorlash kerak.

Diqqat: int kutilgan joyga float berish taqiqlanadi, lekin float kutilgan joyga int berish ruxsat etiladi - chunki bunda ma'lumot yo'qolmaydi.

Taqqoslashdagi tuzoq #

PHP
// == (bo'sh taqqoslash) turlarni AYLANTIRADI
$juftliklar = [
    ["0", 0],
    ["abc", 0],
    ["1", 1],
    [null, false],
    [null, 0],
    ["", null],
    [0.1 + 0.2, 0.3],
];

printf("%-21s %-8s %-8s %s\n", "CHAP", "O'NG", "==", "===");
echo str_repeat("-", 48) . "\n";

foreach ($juftliklar as [$a, $b]) {
    echo rtrim(sprintf(
        "%-21s %-8s %-8s %s",
        var_export($a, true),
        var_export($b, true),
        ($a == $b) ? "true" : "false",
        ($a === $b) ? "true" : "false"
    )) . "\n";
}
Natija
CHAP                  O'NG     ==       ===
------------------------------------------------
'0'                   0        true     false
'abc'                 0        false    false
'1'                   1        true     false
NULL                  false    true     false
NULL                  0        true     false
''                    NULL     true     false
0.30000000000000004   0.3      false    false
Har doim === ishlating

Jadvalning oxirgi qatoriga qarang: 0.1 + 0.2 0.3 ga teng emas, hatto == bilan ham.

Bu PHP ning kamchiligi emas - bu IEEE 754 kasr sonlar standartining tabiati. Deyarli barcha tillarda shunday.

Kasr sonlarni solishtirishning to'g'ri usuli - farqni tekshirish:

PHP
$farq = abs((0.1 + 0.2) - 0.3);
if ($farq < 0.00001) {
    // teng deb hisoblaymiz
}

Qolgan qatorlar esa == ning xavfini ko'rsatadi. PHP 8 da bu ancha yaxshilandi: ilgari "abc" == 0 rost edi, endi esa yolg'on. Lekin "1" == 1 hali ham rost.

Amaliy qoida:

VaziyatOperator
Har qanday taqqoslash===
Turini ham tekshirish kerak===
Ataylab tur aylantirishAvval (int) qiling, keyin ===
Kasr sonlarabs($a - $b) < $aniqlik

== ni ishlatishga sabab topsangiz, deyarli har doim kodni boshqacha yozish yaxshiroq.

PHP turlari va ular bilan ishlash SKALYAR int butun son, 64 bit float kasr, aniq emas string baytlar ketma-ketligi bool true / false qiymat bo'yicha uzatiladi MURAKKAB array tartiblangan xarita object sinf namunasi Massiv - qiymat bo'yicha Obyekt - HAVOLA bo'yicha bu farqni unutmang MAXSUS null qiymat yo'q callable chaqirsa bo'ladigan resource fayl, ulanish null - "hali yo'q" degani, "nol" yoki "bo'sh" emas Eng ko'p uchraydigan xato == turlarni jimgina aylantiradi: "1" == 1 rost, "1" === 1 yolg'on. Yechim: har doim === ishlating. Uch himoya vositasi declare(strict_types=1); turlar jimgina aylanmaydi function f(int $a): string imzo nimani kutayotganini aytadi $a ?? $standart $obj?->usul()
Turlarni aniq belgilash - PHP da eng arzon xato profilaktikasi

null bilan xavfsiz ishlash #

PHP
$sozlamalar = [
    "til"    => "uz",
    "mavzu"  => null,
    "hajm"   => 0,
];

// ?? - faqat null bo'lganda standart qiymat beradi
echo "til:    " . ($sozlamalar["til"]   ?? "standart") . "\n";
echo "mavzu:  " . ($sozlamalar["mavzu"] ?? "standart") . "\n";
echo "hajm:   " . ($sozlamalar["hajm"]  ?? "standart") . "\n";
echo "yo'q:   " . ($sozlamalar["rang"]  ?? "standart") . "\n";

echo "\n";
echo "Taqqoslash uchun ?: (Elvis) - BO'SH bo'lganda ishlaydi:\n";
echo "  hajm ?: standart = " . ($sozlamalar["hajm"] ?: "standart") . "\n";
echo "  (0 bo'sh deb hisoblanadi - odatda BU KERAK EMAS)\n";

echo "\n";
// ??= faqat mavjud bo'lmasa tayinlaydi
$sozlamalar["rang"] ??= "ko'k";
$sozlamalar["til"]  ??= "en";
echo "rang qo'shildi: " . $sozlamalar["rang"] . "\n";
echo "til o'zgarmadi: " . $sozlamalar["til"] . "\n";
Natija
til:    uz
mavzu:  standart
hajm:   0
yo'q:   standart

Taqqoslash uchun ?: (Elvis) - BO'SH bo'lganda ishlaydi:
  hajm ?: standart = standart
  (0 bo'sh deb hisoblanadi - odatda BU KERAK EMAS)

rang qo'shildi: ko'k
til o'zgarmadi: uz
?? va ?: - qaysi birini tanlash

Bu ikkisi boshqacha ishlaydi va ularni chalkashtirish keng tarqalgan xato:

OperatorQachon standart qiymat beradi
??Faqat null yoki mavjud emas
?:Har qanday bo'sh qiymatda

"Bo'sh" deganda PHP quyidagilarni tushunadi:

QiymatBo'shmi
0Ha
"0"Ha
""Ha
[]Ha
falseHa
nullHa

Birinchi ikki qator xavfli. Foydalanuvchi haqiqatan 0 kiritgan bo'lsa (masalan chegirma foizi), ?: uni tashlab yuboradi va standart qiymatni qo'yadi.

Qoida: deyarli har doim ?? ishlating.

??= esa "faqat yo'q bo'lsa tayinla" degani va sozlamalarni to'ldirishda juda qulay.

Turga oshkora aylantirish #

PHP
$kiritilganlar = ["42", "3.9", "abc", "", "0", "12abc"];

printf("%-8s %-8s %-10s %-8s %s\n", "KIRISH", "(int)", "(float)", "(bool)", "XAVFSIZ");
echo str_repeat("-", 50) . "\n";

foreach ($kiritilganlar as $k) {
    // filter_var - haqiqiy tekshiruv, jimgina aylantirish emas
    $xavfsiz = filter_var($k, FILTER_VALIDATE_INT);
    printf(
        "%-8s %-8d %-10s %-8s %s\n",
        var_export($k, true),
        (int) $k,
        (float) $k,
        ((bool) $k) ? "true" : "false",
        $xavfsiz === false ? "rad etildi" : (string) $xavfsiz
    );
}
Natija
KIRISH   (int)    (float)    (bool)   XAVFSIZ
--------------------------------------------------
'42'     42       42         true     42
'3.9'    3        3.9        true     rad etildi
'abc'    0        0          true     rad etildi
''       0        0          false    rad etildi
'0'      0        0          false    0
'12abc'  12       12         true     rad etildi
(int) foydalanuvchi kiritgan ma'lumot uchun yaramaydi

Jadvalning oxirgi ikki ustunini solishtiring.

(int) "abc" 0 qaytaradi - hech qanday xato yo'q. (int) "12abc" esa 12 qaytaradi.

Endi tasavvur qiling: foydalanuvchi buyurtma miqdoriga "abc" yozdi. (int) bilan siz 0 olasiz va bu "nol dona" degan ma'noni bildiradi - ya'ni xato yo'qoladi.

filter_var($k, FILTER_VALIDATE_INT) esa false qaytaradi va siz muammoni bilib turasiz.

ManbaUsul
O'z kodingizdagi qiymat(int) mumkin
$_POST, $_GETfilter_var
Fayl yoki APIfilter_var yoki tekshiruv

Diqqat: filter_var false qaytaradi, lekin "0" uchun 0 qaytaradi - va 0 ham "bo'sh". Shuning uchun natijani === false bilan solishtiring, ! bilan emas.

9-bo'limda validatsiyani batafsil ko'ramiz.

Doimiylar #

PHP
// const - kompilyatsiya paytida, sinf ichida ham ishlaydi
const SOLIQ_FOIZI = 12;
const SAYT_NOMI = "Softromeda";

// define() - ish paytida, shart ichida ishlatish mumkin
define("MAKS_YUKLAMA", 5 * 1024 * 1024);

echo "Sayt: " . SAYT_NOMI . "\n";
echo "Soliq: " . SOLIQ_FOIZI . "%\n";
echo "Maksimal yuklama: " . MAKS_YUKLAMA . " bayt\n";
echo "Ya'ni: " . round(MAKS_YUKLAMA / 1024 / 1024, 1) . " MB\n";

echo "\n";
echo "Doimiy mavjudmi: " . (defined("SOLIQ_FOIZI") ? "ha" : "yo'q") . "\n";
echo "Bunday doimiy yo'q: " . (defined("YOQ_DOIMIY") ? "ha" : "yo'q") . "\n";

echo "\n";
// Massiv ham doimiy bo'la oladi
const RUXSATLAR = ["o'qish", "yozish", "o'chirish"];
echo "Ruxsatlar: " . implode(", ", RUXSATLAR) . "\n";
echo "Birinchisi: " . RUXSATLAR[0] . "\n";
Natija
Sayt: Softromeda
Soliq: 12%
Maksimal yuklama: 5242880 bayt
Ya'ni: 5 MB

Doimiy mavjudmi: ha
Bunday doimiy yo'q: yo'q

Ruxsatlar: o'qish, yozish, o'chirish
Birinchisi: o'qish
const va define() orasidagi farq
constdefine()
Qachon ishlaydiKompilyatsiya paytidaIsh paytida
if ichidaMumkin emasMumkin
Sinf ichidaMumkinMumkin emas
Nom katta-kichikligiDoim sezgirDoim sezgir
TezlikBiroz tezroqBiroz sekinroq

Amaliy tavsiya: const ni ishlating. define() ni faqat doimiy nomi yoki qiymati ish paytida aniqlanadigan kam uchraydigan holatlarda ishlating.

Doimiy nomlarini KATTA HARFLAR bilan yozish - butun PHP olamida qabul qilingan an'ana. Bu kodni o'qiyotganda o'zgaruvchi bilan doimiyni darhol ajratish imkonini beradi.

19-bo'limda enum ni ko'ramiz - bog'liq doimiylar to'plami uchun u doimiylardan ancha yaxshiroq.

Amaliy topshiriq
  1. Sakkiz turdagi o'zgaruvchi yarating va get_debug_type() bilan chiqaring.
  2. gettype() bilan solishtiring - qaysi nomlar farq qiladi?
  3. declare(strict_types=1) bilan funksiyaga satr uzating - nima bo'ladi?
  4. Xuddi shu kodni declare siz sinab ko'ring.
  5. kvadrat(7.9) ni qat'iy va oddiy rejimda solishtiring.
  6. "1" == 1 va "1" === 1 natijasini tekshiring.
  7. 0.1 + 0.2 === 0.3 ni sinab ko'ring va sababini tushuntiring.
  8. ?? va ?: ni 0 qiymat bilan solishtiring.
  9. (int) "12abc" va filter_var("12abc", FILTER_VALIDATE_INT) ni solishtiring.
  10. const bilan massiv doimiy yarating va elementiga murojaat qiling.

Xulosa #

  • PHP dinamik turli, lekin turlar bor va ular bilan ishlash muhim.
  • get_debug_type() turlarni kodda yozilganidek nomlaydi - gettype() dan yaxshiroq.
  • declare(strict_types=1) har bir fayl boshida bo'lsin - u faqat o'sha faylga ta'sir qiladi.
  • Qat'iy rejimsiz kvadrat(7.9) jimgina 49 beradi - kasr yo'qoladi.
  • == turlarni aylantiradi - har doim === ishlating.
  • 0.1 + 0.2 !== 0.3 - kasr sonlarni farq orqali solishtiring.
  • ?? faqat null da ishlaydi, ?: esa har qanday bo'sh qiymatda - odatda ?? kerak.
  • 0 va "0" PHP da bo'sh hisoblanadi - bu tuzoqning asosiy manbai.
  • Foydalanuvchi ma'lumoti uchun (int) emas, filter_var ishlating.
  • filter_var natijasini === false bilan tekshiring.
  • Doimiylar uchun const, nomlari KATTA HARFLARDA.

Keyingi bo'limda satrlar bilan ishlashni - qidirish, almashtirish, bo'lish va formatlashni o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.