Namespace va autoload

~15 daq · PHP · OOP — Ob'ektga yo'naltirilgan PHP

Muammodan boshlaylik

Loyihangiz o'sdi: 40 ta class, har biri alohida faylda. Har bir sahifa boshida:

<?php

require_once __DIR__ . '/src/Mahsulot.php';
require_once __DIR__ . '/src/Savat.php';
require_once __DIR__ . '/src/Buyurtma.php';
require_once __DIR__ . '/src/BuyurtmaHolati.php';
require_once __DIR__ . '/src/PaymeTolov.php';
// ... yana 15 ta

Yangi class qo'shsangiz — kerakli sahifalarga require qo'shishni unutasiz. Bundan tashqari, siz Logger classini yozdingiz, keyin o'rnatgan kutubxonada ham Logger bor:

Fatal error: Cannot declare class Logger, because the name is already in use

Ikki muammo, ikki yechim: namespace — nomlar to'qnashuvi uchun, autoload — require lar uchun.


Namespace — nomlar uchun "familiya"

Sinfda ikkita Aziz bor. O'qituvchi "Aziz Karimov" va "Aziz Toshev" deb ajratadi. Namespace — classlarning familiyasi:

<?php
// src/Dokon/Logger.php

namespace Dokon;

class Logger
{
    public function yoz(string $xabar): void { /* ... */ }
}

Endi bu classning to'liq nomi — Dokon\Logger. Boshqa kutubxonadagi Monolog\Logger bilan to'qnashmaydi.

Namespace ichma-ich bo'lishi mumkin:

<?php

namespace Dokon\Tolov;

class PaymeTolov { }   // to'liq nomi: Dokon\Tolov\PaymeTolov

[!INFO] namespace faylning birinchi buyrug'i bo'lishi kerak (declare(strict_types=1); dan tashqari). Namespace da \ (teskari slash) ishlatiladi.


use — qisqa nom bilan ishlatish

<?php

namespace Dokon\Controller;

use Dokon\Tolov\PaymeTolov;
use Dokon\Tolov\TolovTizimi;
use Dokon\Logger;
use Monolog\Logger as MonologLogger;   // nomini o'zgartirib olish

class BuyurtmaController
{
    public function __construct(
        private TolovTizimi $tolov,
        private Logger $logger,
    ) {}
}

use — "bu faylda PaymeTolov deganimda, Dokon\Tolov\PaymeTolov ni nazarda tutaman". as — bir xil nomli ikki classni ajratish uchun.

PHP ning o'z classlari

Namespace ichida PHP ning o'rnatilgan classlari oldiga \ qo'yish yoki use qilish kerak:

<?php

namespace Dokon;

$sana = new DateTimeImmutable();
// Error: Class "Dokon\DateTimeImmutable" not found

$sana = new \DateTimeImmutable();   // ✅ global namespace dan

Yoki fayl boshida use DateTimeImmutable;.


Autoload — classlarni avtomatik yuklash

PHP kodda noma'lum class uchrasa (masalan, new Dokon\Savat()), u to'xtashdan oldin sizdan so'raydi: "bu classni qayerdan topay?". Bu savolga javob beruvchi funksiya — autoloader:

<?php
// public/index.php

spl_autoload_register(function (string $class): void {
    // "Dokon\Tolov\PaymeTolov" → "src/Tolov/PaymeTolov.php"
    $prefiks = 'Dokon\\';
    $papka = __DIR__ . '/../src/';

    if (!str_starts_with($class, $prefiks)) {
        return;   // boshqa namespace — bu autoloader ning ishi emas
    }

    $nisbiy = substr($class, strlen($prefiks));
    $fayl = $papka . str_replace('\\', '/', $nisbiy) . '.php';

    if (is_file($fayl)) {
        require $fayl;
    }
});

// Endi birorta ham require kerak emas:
$savat = new Dokon\Savat();
$tolov = new Dokon\Tolov\PaymeTolov();

Autoloader classni faqat birinchi marta kerak bo'lganda yuklaydi. Ishlatilmagan classlar umuman yuklanmaydi — bu tezlik uchun ham foydali.


PSR-4 — umumiy qoida

Autoloader ishlashi uchun namespace va papka tuzilmasi bir-biriga mos bo'lishi kerak. Bu qoida PSR-4 standarti deyiladi:

Namespace                    →  Fayl
Dokon\Savat                  →  src/Savat.php
Dokon\Tolov\PaymeTolov       →  src/Tolov/PaymeTolov.php
Dokon\Model\Foydalanuvchi    →  src/Model/Foydalanuvchi.php

Qoidalar:

  • Bitta fayl — bitta class
  • Fayl nomi = class nomi (katta-kichik harf ham!)
  • Namespace qismlari = papkalar

Odatiy loyiha tuzilmasi:

dokon/
├── public/
│   └── index.php          ← veb-server faqat shu papkani ko'radi
├── src/
│   ├── Savat.php          ← namespace Dokon;
│   ├── Model/
│   │   └── Mahsulot.php   ← namespace Dokon\Model;
│   └── Tolov/
│       ├── TolovTizimi.php
│       └── PaymeTolov.php ← namespace Dokon\Tolov;
└── config.php

public/ — yagona ochiq papka. src/, config.php brauzerdan umuman ko'rinmaydi. Bu xavfsizlik uchun juda muhim.


Composer bilan — amaliy usul

O'z autoloader ingizni yozish shart emas. Composer (39-dars) buni avtomatik qiladi. composer.json:

{
    "autoload": {
        "psr-4": {
            "Dokon\\": "src/"
        }
    }
}
composer dump-autoload

public/index.php:

<?php

require __DIR__ . '/../vendor/autoload.php';

$savat = new Dokon\Savat();   // hammasi ishlaydi

Bitta qator — va barcha classlaringiz hamda o'rnatilgan kutubxonalar avtomatik yuklanadi. Zamonaviy PHP loyihalarning 100% i shunday ishlaydi.


Nima uchun shunday?

Nima uchun namespace ajratgichi \, boshqa tillardagidek . yoki :: emas?

PHP da . — string birlashtirish, :: — static murojaat uchun allaqachon band edi. 2008-yilda namespace qo'shilayotganda ko'p variantlar muhokama qilindi va to'qnashmaydigan yagona belgi sifatida \ tanlandi. Ko'pchilik uni yoqtirmaydi (string ichida 'Dokon\\Savat' deb ikki marta yozish kerak), lekin endi bu o'zgarmaydi.


Tez-tez uchraydigan xatolar

Class topilmadi:

Error: Class "Dokon\Model\Mahsulot" not found

Tekshiring: fayl to'g'ri papkadami? Fayl nomi class nomi bilan aynan mosmi (mahsulot.php ≠ Mahsulot.php — Windows da ishlaydi, Linux serverda yo'q)? Faylda namespace to'g'ri yozilganmi?

use ni unutish — PHP classni joriy namespace ichidan qidiradi.

Namespace dagi o'rnatilgan classlar — \DateTimeImmutable, \PDO, \Exception — \ yoki use kerak.


Xulosa

Eslab qoling:

  • namespace Dokon\Tolov; — classning "familiyasi", nomlar to'qnashmaydi
  • use Dokon\Tolov\PaymeTolov; — qisqa nom bilan ishlatish; as — nomini o'zgartirish
  • Namespace ichida PHP classlari uchun \ yoki use
  • spl_autoload_register — classlarni avtomatik yuklash
  • PSR-4: namespace = papka, class nomi = fayl nomi
  • Amalda: Composer + require 'vendor/autoload.php'

Keyingi dars

34-dars: MySQL ga kirish — jadval, CRUD so'rovlar