14-bo‘lim
Nomlar fazosi va avtoyuklash
namespace, use, PSR-4 avtoyuklash, Composer asoslari va loyihani fayllarga to'g'ri taqsimlash.
Ushbu bo‘lim mundarijasi
Loyiha o'sganda ikki muammo paydo bo'ladi: sinf nomlari
to'qnashadi va har bir faylni qo'lda require qilish
imkonsiz bo'lib qoladi.
Ikkalasini ham nomlar fazosi va avtoyuklash hal qiladi.
Nom to'qnashuvi muammosi #
Ikkita kutubxonada bir xil nomli sinf bo'lsa nima bo'ladi? Nomlar fazosisiz - to'qnashuv va xato.
Nomlar fazosi bilan esa ular bemalol birga yashaydi. Quyida uch alohida fayl:
<?php
// src/Jurnal/Yozuvchi.php
declare(strict_types=1);
namespace Ilova\Jurnal;
final class Yozuvchi
{
public function yoz(string $x): string
{
return "[fayl jurnali] {$x}";
}
}
<?php
// src/Hisobot/Yozuvchi.php <- AYNAN SHU NOM, boshqa fazo
declare(strict_types=1);
namespace Ilova\Hisobot;
final class Yozuvchi
{
public function yoz(string $x): string
{
return "[hisobot] {$x}";
}
}
<?php
// public/index.php
declare(strict_types=1);
require __DIR__ . "/../vendor/autoload.php";
$a = new \Ilova\Jurnal\Yozuvchi();
$b = new \Ilova\Hisobot\Yozuvchi();
echo $a->yoz("server ishga tushdi"), "\n"; // [fayl jurnali] server ishga tushdi
echo $b->yoz("oylik savdo"), "\n"; // [hisobot] oylik savdo
Ikkala sinf ham Yozuvchi deb ataladi, lekin ularning
to'liq nomi har xil:
| Qisqa nom | To'liq nom |
|---|---|
Yozuvchi | Ilova\Jurnal\Yozuvchi |
Yozuvchi | Ilova\Hisobot\Yozuvchi |
PHP uchun sinfning haqiqiy identifikatori - to'liq nom. Qisqa nom shunchaki qulaylik.
namespace birinchi bajariluvchi qator bo'lishi
kerak - undan oldin faqat declare(strict_types=1);
kelishi mumkin.
<?php
declare(strict_types=1);
namespace Ilova\Jurnal;
final class Yozuvchi { ... }
Texnik jihatdan figurali qavsli shakl ham bor
(namespace X { ... }) va u bitta faylga bir necha
fazoni sig'dirishga imkon beradi. Lekin u amalda
deyarli ishlatilmaydi - avtoyuklash bilan mos
kelmaydi.
Qoida: bitta fayl - bitta sinf - bitta nomlar fazosi. Aynan shu qoida keyingi bo'limdagi avtoyuklashni mumkin qiladi.
$obyekt::class sintaksisi (PHP 8) obyektning to'liq
sinf nomini beradi. PHP 8 gacha get_class($obyekt)
yozilardi.
use bilan import #
To'liq nomni har safar yozish charchatadi. use uni
fayl boshida bir marta e'lon qilish imkonini beradi:
<?php
// src/Xizmat/BuyurtmaXizmati.php
declare(strict_types=1);
namespace Ilova\Xizmat;
use Ilova\Model\Foydalanuvchi;
use Ilova\Model\Buyurtma as Zakaz; // taxallus
use DateTimeImmutable; // ichki sinfni ham import qilamiz
final class BuyurtmaXizmati
{
public function yarat(Foydalanuvchi $f, int $id): string
{
$b = new Zakaz($id);
$vaqt = new DateTimeImmutable("2024-09-01 10:00:00");
return sprintf("#%d - %s (%s)", $b->id, $f->ism, $vaqt->format("d.m.Y"));
}
}
PHP nomni qanday hal qilishini quyidagi kod modellashtiradi:
// PHP nomni hal qilish qoidalari (soddalashtirilgan)
function nomniHal(string $yozilgan, string $joriyFazo, array $importlar): string
{
// 1. \ bilan boshlansa - bu MUTLAQ nom, o'zgartirilmaydi
if (str_starts_with($yozilgan, "\\")) {
return ltrim($yozilgan, "\\") . " (mutlaq)";
}
// 2. Birinchi bo'lak import qilinganmi?
$boshi = explode("\\", $yozilgan)[0];
if (isset($importlar[$boshi])) {
$qolgan = substr($yozilgan, strlen($boshi));
return $importlar[$boshi] . $qolgan . " (use orqali)";
}
// 3. Aks holda - joriy fazoga qo'shiladi
return $joriyFazo . "\\" . $yozilgan . " (joriy fazodan)";
}
$joriyFazo = "Ilova\\Xizmat";
$importlar = [
"Foydalanuvchi" => "Ilova\\Model\\Foydalanuvchi",
"Zakaz" => "Ilova\\Model\\Buyurtma",
];
$yozuvlar = [
"Foydalanuvchi",
"Zakaz",
"Yordamchi",
"Ichki\\Sinf",
"\\DateTimeImmutable",
];
printf("%-22s %s\n", "KODDA YOZILGAN", "PHP QANDAY TUSHUNADI");
echo str_repeat("-", 62) . "\n";
foreach ($yozuvlar as $y) {
printf("%-22s %s\n", $y, nomniHal($y, $joriyFazo, $importlar));
}
KODDA YOZILGAN PHP QANDAY TUSHUNADI
--------------------------------------------------------------
Foydalanuvchi Ilova\Model\Foydalanuvchi (use orqali)
Zakaz Ilova\Model\Buyurtma (use orqali)
Yordamchi Ilova\Xizmat\Yordamchi (joriy fazodan)
Ichki\Sinf Ilova\Xizmat\Ichki\Sinf (joriy fazodan)
\DateTimeImmutable DateTimeImmutable (mutlaq)
\ kerakNomlar fazosi ichida strlen("abc") yozsangiz, PHP
avval Ilova\Xizmat\strlen ni qidiradi, topmasa
globalga tushadi.
Sinflar uchun esa bunday emas: new DateTime()
nomlar fazosi ichida Ilova\Xizmat\DateTime degani va
u topilmaydi.
| Nima | Global ga tushadimi |
|---|---|
Funksiya (strlen) | Ha |
Doimiy (PHP_EOL) | Ha |
Sinf (DateTime) | Yo'q - xato beradi |
Shuning uchun ikki yechim bor:
$d = new \DateTimeImmutable(); // 1. oldiga \ qo'yish
use DateTimeImmutable; // 2. faylning boshida import
$d = new DateTimeImmutable();
Ikkinchisi afzal - u fayl boshida barcha bog'liqliklarni ko'rsatadi.
Funksiyalar uchun \ qo'yish tezlikni biroz
oshiradi (qidiruv bosqichi tushib qoladi), lekin bu
mikro-optimallashtirish - kod o'qishligi muhimroq.
Avtoyuklagichni qo'lda yozish #
// Composer nima qilishini tushunish uchun oddiy PSR-4 avtoyuklagich
$xaritalash = [
"App\\" => "/loyiha/src/",
"Test\\" => "/loyiha/tests/",
];
function yolniHisobla(string $sinf, array $xaritalash): ?string
{
foreach ($xaritalash as $prefiks => $katalog) {
if (!str_starts_with($sinf, $prefiks)) {
continue;
}
// Prefiksni katalog bilan almashtiramiz
$qolgan = substr($sinf, strlen($prefiks));
$yol = $katalog . str_replace("\\", "/", $qolgan) . ".php";
return $yol;
}
return null;
}
$sinflar = [
"App\\Model\\Foydalanuvchi",
"App\\Xizmat\\Tolov\\Karta",
"Test\\Model\\FoydalanuvchiTest",
"Boshqa\\Kutubxona\\Sinf",
];
printf("%-34s %s\n", "SINF", "FAYL YO'LI");
echo str_repeat("-", 74) . "\n";
foreach ($sinflar as $s) {
$yol = yolniHisobla($s, $xaritalash);
printf("%-34s %s\n", $s, $yol ?? "(xaritalashda yo'q)");
}
echo "\n";
echo "Haqiqiy avtoyuklagich shunday ro'yxatdan o'tkaziladi:\n";
echo " spl_autoload_register(function (string \$sinf): void {\n";
echo " \$yol = yolniHisobla(\$sinf, \$xaritalash);\n";
echo " if (\$yol !== null && is_file(\$yol)) {\n";
echo " require \$yol;\n";
echo " }\n";
echo " });\n";
SINF FAYL YO'LI
--------------------------------------------------------------------------
App\Model\Foydalanuvchi /loyiha/src/Model/Foydalanuvchi.php
App\Xizmat\Tolov\Karta /loyiha/src/Xizmat/Tolov/Karta.php
Test\Model\FoydalanuvchiTest /loyiha/tests/Model/FoydalanuvchiTest.php
Boshqa\Kutubxona\Sinf (xaritalashda yo'q)
Haqiqiy avtoyuklagich shunday ro'yxatdan o'tkaziladi:
spl_autoload_register(function (string $sinf): void {
$yol = yolniHisobla($sinf, $xaritalash);
if ($yol !== null && is_file($yol)) {
require $yol;
}
});
Yuqoridagi kod nima sodir bo'layotganini ko'rsatish
uchun. Amalda composer.json yoziladi:
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
Keyin bir marta:
composer dump-autoload
Va loyihaning kirish faylida bir qator:
require __DIR__ . "/vendor/autoload.php";
Shundan keyin src/ ichidagi har qanday sinf
avtomatik topiladi.
Composer yana bir ish qiladi - kutubxona o'rnatadi:
| Buyruq | Nima qiladi |
|---|---|
composer require monolog/monolog | Kutubxona qo'shadi |
composer install | composer.lock bo'yicha o'rnatadi |
composer update | Yangi versiyalarga yangilaydi |
composer dump-autoload -o | Avtoyuklashni tezlashtiradi |
composer.lock ni git ga qo'shing - u har bir
mashinada aynan bir xil versiyalar o'rnatilishini
kafolatlaydi. vendor/ papkasini esa .gitignore ga
qo'ying.
Loyiha tuzilmasi #
$tuzilma = [
"loyiha/" => [
"public/" => ["index.php" => "yagona kirish nuqtasi", ".htaccess" => "yo'naltirish"],
"src/" => [
"Model/" => ["Foydalanuvchi.php" => "App\\Model\\Foydalanuvchi"],
"Xizmat/" => ["TolovXizmati.php" => "App\\Xizmat\\TolovXizmati"],
"Kontroller/" => ["BoshKontroller.php" => "App\\Kontroller\\BoshKontroller"],
],
"shablon/" => ["bosh.php" => "HTML shabloni"],
"config/" => ["sozlama.php" => "sozlamalar"],
"tests/" => ["FoydalanuvchiTest.php" => "Test\\FoydalanuvchiTest"],
"vendor/" => ["autoload.php" => "Composer yaratadi - git ga QO'SHILMAYDI"],
"composer.json" => "bog'liqliklar ro'yxati",
".env" => "maxfiy sozlamalar - git ga QO'SHILMAYDI",
],
];
function chiz(array $t, int $daraja = 0): void
{
foreach ($t as $nom => $ichi) {
$chekinish = str_repeat(" ", $daraja);
if (is_array($ichi)) {
echo "{$chekinish}{$nom}\n";
chiz($ichi, $daraja + 1);
} else {
printf("%s%-22s %s\n", $chekinish, $nom, "# {$ichi}");
}
}
}
chiz($tuzilma);
loyiha/
public/
index.php # yagona kirish nuqtasi
.htaccess # yo'naltirish
src/
Model/
Foydalanuvchi.php # App\Model\Foydalanuvchi
Xizmat/
TolovXizmati.php # App\Xizmat\TolovXizmati
Kontroller/
BoshKontroller.php # App\Kontroller\BoshKontroller
shablon/
bosh.php # HTML shabloni
config/
sozlama.php # sozlamalar
tests/
FoydalanuvchiTest.php # Test\FoydalanuvchiTest
vendor/
autoload.php # Composer yaratadi - git ga QO'SHILMAYDI
composer.json # bog'liqliklar ro'yxati
.env # maxfiy sozlamalar - git ga QO'SHILMAYDI
public/ veb orqali ochiq bo'lsinBu xavfsizlikning eng muhim tuzilmaviy qaroridir.
Veb-server hujjat ildizi (document root) public/
ga qaratilsin. Shunda src/, config/, .env va
vendor/ brauzerdan umuman ochilmaydi.
Noto'g'ri sozlamada nima bo'ladi:
| Manzil | Nima ochiladi |
|---|---|
saytim.uz/.env | Baza paroli va API kalitlari |
saytim.uz/config/sozlama.php | Sozlamalar |
saytim.uz/composer.json | Ishlatilayotgan kutubxonalar |
saytim.uz/.git/config | Butun git tarixi |
Birinchi qator - eng ko'p uchraydigan va eng og'ir
zaiflik. .env fayli oddiy matn va PHP uni
bajarmaydi - brauzer uni shunchaki ko'rsatadi.
Tekshirish juda oson: saytingizga /.env qo'shib
oching. Agar mazmun ko'rinsa - darhol tuzating va
barcha parollarni almashtiring.
Apache uchun public/.htaccess, Nginx uchun esa
root /loyiha/public; sozlamasi kerak.
- Ikki xil nomlar fazosida bir xil nomli sinf yarating.
- Ularni to'liq nom bilan ishlatib ko'ring.
usebilan import qiling va qisqa nom bilan chaqiring.asbilan taxallus bering.- Nomlar fazosi ichida
new DateTime()yozing - xato chiqdimi? - Oldiga
\qo'shib tuzating. - PSR-4 qoidasiga ko'ra
App\Model\Buyurtmaqaysi faylda bo'lishini ayting. spl_autoload_registerbilan oddiy avtoyuklagich yozing.composer.jsonyarating vadump-autoloadni bajaring.- Saytingizga
/.envbilan murojaat qilib, ochilmasligini tekshiring.
Xulosa #
- Nomlar fazosi bir xil nomli sinflarning birga yashashiga imkon beradi.
- Qoida: bitta fayl - bitta sinf - bitta nomlar fazosi,
namespacebirinchi qatorda. usebilan import qiling;astaxallus beradi.- Nomlar fazosi ichida funksiyalar globalga tushadi, sinflar esa yo'q.
new DateTime()nomlar fazosi ichida ishlamaydi -\DateTimeyokiusekerak.- PSR-4: nomlar fazosi prefiksi katalogga, qolgan qismi yo'lga aylanadi.
- Fayl nomi sinf nomi bilan aynan bir xil bo'lsin - Linux katta-kichik harfni ajratadi.
- Composer avtoyuklashni ham, kutubxonalarni ham boshqaradi.
composer.lockni git ga qo'shing,vendor/ni esa qo'shmang.- Veb-server ildizi
public/ga qaratilsin - aks holda.envbrauzerdan ochiladi.
Keyingi bo'limda xatolar va istisnolarni to'g'ri boshqarishni 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.