3-bo‘lim
Turlar va o'zgaruvchilar
PHP ning sakkiz turi, qat'iy turlar rejimi, taqqoslashdagi tuzoqlar va null bilan xavfsiz ishlash.
Ushbu bo‘lim mundarijasi
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 #
// Har bir misol qat'iy turlar rejimida ishlaydi.
$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));
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() farqiPHP 8 da get_debug_type() qo'shildi va u eski
gettype() dan yaxshiroq:
| Qiymat | gettype() | get_debug_type() |
|---|---|---|
42 | integer | int |
3.14 | double | float |
true | boolean | bool |
new Foo() | object | Foo |
null | NULL | null |
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 #
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";
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'ladiBu qatorsiz PHP yuqoridagi chaqiruvni jimgina qabul
qiladi va "7" ni 7 ga aylantiradi. Qulay ko'rinadi -
lekin quyidagi holatlarni ham qabul qiladi:
| Chaqiruv | Qat'iy rejimsiz | Qat'iy rejimda |
|---|---|---|
kvadrat("7") | 49 | TypeError |
kvadrat(7.9) | 49 (kasr yo'qoladi!) | TypeError |
kvadrat(true) | 1 | TypeError |
kvadrat("7abc") | 49 + ogohlantirish | TypeError |
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 #
// == (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";
}
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
=== ishlatingJadvalning 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:
$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:
| Vaziyat | Operator |
|---|---|
| Har qanday taqqoslash | === |
| Turini ham tekshirish kerak | === |
| Ataylab tur aylantirish | Avval (int) qiling, keyin === |
| Kasr sonlar | abs($a - $b) < $aniqlik |
== ni ishlatishga sabab topsangiz, deyarli har doim
kodni boshqacha yozish yaxshiroq.
null bilan xavfsiz ishlash #
$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";
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 tanlashBu ikkisi boshqacha ishlaydi va ularni chalkashtirish keng tarqalgan xato:
| Operator | Qachon standart qiymat beradi |
|---|---|
?? | Faqat null yoki mavjud emas |
?: | Har qanday bo'sh qiymatda |
"Bo'sh" deganda PHP quyidagilarni tushunadi:
| Qiymat | Bo'shmi |
|---|---|
0 | Ha |
"0" | Ha |
"" | Ha |
[] | Ha |
false | Ha |
null | Ha |
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 #
$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
);
}
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 yaramaydiJadvalning 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.
| Manba | Usul |
|---|---|
| O'z kodingizdagi qiymat | (int) mumkin |
$_POST, $_GET | filter_var |
| Fayl yoki API | filter_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 #
// 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";
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 farqconst | define() | |
|---|---|---|
| Qachon ishlaydi | Kompilyatsiya paytida | Ish paytida |
if ichida | Mumkin emas | Mumkin |
| Sinf ichida | Mumkin | Mumkin emas |
| Nom katta-kichikligi | Doim sezgir | Doim sezgir |
| Tezlik | Biroz tezroq | Biroz 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.
- Sakkiz turdagi o'zgaruvchi yarating va
get_debug_type()bilan chiqaring. gettype()bilan solishtiring - qaysi nomlar farq qiladi?declare(strict_types=1)bilan funksiyaga satr uzating - nima bo'ladi?- Xuddi shu kodni
declaresiz sinab ko'ring. kvadrat(7.9)ni qat'iy va oddiy rejimda solishtiring."1" == 1va"1" === 1natijasini tekshiring.0.1 + 0.2 === 0.3ni sinab ko'ring va sababini tushuntiring.??va?:ni0qiymat bilan solishtiring.(int) "12abc"vafilter_var("12abc", FILTER_VALIDATE_INT)ni solishtiring.constbilan 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)jimgina49beradi - kasr yo'qoladi. ==turlarni aylantiradi - har doim===ishlating.0.1 + 0.2 !== 0.3- kasr sonlarni farq orqali solishtiring.??faqatnullda ishlaydi,?:esa har qanday bo'sh qiymatda - odatda??kerak.0va"0"PHP da bo'sh hisoblanadi - bu tuzoqning asosiy manbai.- Foydalanuvchi ma'lumoti uchun
(int)emas,filter_varishlating. filter_varnatijasini=== falsebilan tekshiring.- Doimiylar uchun
const, nomlari KATTA HARFLARDA.
Keyingi bo'limda satrlar bilan ishlashni - qidirish, almashtirish, bo'lish va formatlashni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.