İçeriğe geç
Muhammet Şafak
Diller 3 dk okuma

PHP'de namespace ile kodu düzenli tutmak

İsim çakışmalarını bitiren, kütüphane çağına uygun kod organizasyonu: PHP namespace kullanımı ve use ifadesi.


Composer ve PSR-4 otomatik yüklemeyi oturttuktan sonra bir sorunla daha yüzleşmek gerekiyor: isim çakışmaları (name collisions). Kendi yazdığım User sınıfı ile kullandığım bir kütüphanenin User sınıfı aynı projede bir arada bulunmak zorunda kalırsa ne olur? PHP bunu çözmeden önce bu sorunla sık sık karşılaşılırdı.

Ad alanı (Namespace), sınıfları, fonksiyonları ve sabitleri mantıksal gruplar altında organize etmenizi ve isim çakışmalarını önlemenizi sağlayan PHP 5.3 ile gelen bir özelliktir. PHP 5.3 çok eskide kaldı ama namespace kullanımı ekosistemde ancak Composer ve PSR standartlarıyla birlikte yaygınlaştı.

Temel kullanım

Bir dosyanın en üstüne namespace bildirimi yazılır:

<?php
namespace App\Models;

class User
{
    public $name;
    public $email;
}

Bu sınıfın tam adı artık App\Models\User. Başka bir dosyada aynı isimde bir sınıf tanımlasanız bile çakışma olmuyor çünkü farklı ad alanlarında yaşıyorlar.

<?php
namespace Vendor\Auth;

class User
{
    // Bu, App\Models\User ile çakışmaz
    public function authenticate($credentials) { ... }
}

use ifadesi ile kısaltma

Her kullanımda tam ad alanını yazmak uzun ve okunaksız. use ifadesi bunu kısaltır:

<?php
namespace App\Http;

use App\Models\User;
use App\Services\Mailer;

class UserController
{
    public function store()
    {
        $user = new User(); // App\Models\User
        $mailer = new Mailer();
    }
}

use ile alınan sınıflara kısa adlarıyla erişiyorsunuz. İki farklı namespace’den aynı isimde sınıf kullanmanız gerekirse takma ad (alias) tanımlayabilirsiniz:

<?php
use App\Models\User as AppUser;
use Vendor\Auth\User as AuthUser;

$appUser = new AppUser();
$authUser = new AuthUser();

Alias kullanmak ilk başta garip görünüyor; ama aynı dosyada iki farklı User sınıfıyla çalışmak zorunda kaldığınızda başka bir çözüm yok. Bu durum gerçekten oluyor — özellikle bir kütüphanenin kendi modelleri ile uygulamanın modelleri aynı dosyada birlikte kullanıldığında.

Namespace hiyerarşisi

Namespace’ler iç içe olabilir ve proje yapısını yansıtır. PSR-4 ile bu hiyerarşi dizin yapısına birebir karşılık gelir:

App\
  Http\
    Controllers\
      UserController     → src/Http/Controllers/UserController.php
      PostController     → src/Http/Controllers/PostController.php
  Models\
    User                 → src/Models/User.php
  Services\
    Mailer               → src/Services/Mailer.php

Bu yapı büyük projelerde gezinmeyi kolaylaştırıyor. Nerede olduğunuzu bilmeden bile namespace’e bakarak dosyanın ne işe yaradığını anlıyorsunuz.

Projeye sonradan katılan biri App\Http\Controllers\UserController ismini gördüğünde dosyanın nerede olduğunu bulmak için dosya araması yapmak zorunda kalmıyor; namespace zaten yolu söylüyor. Bu okunabilirlik getirisi zamanla çok değerli hale geliyor.

Global namespace

PHP’nin yerleşik sınıfları global ad alanında yaşar. Namespace içindeyken yerleşik bir sınıfa erişmek için başına \ koyuyorsunuz:

<?php
namespace App\Services;

class FileHandler
{
    public function open($path)
    {
        // PHP'nin yerleşik Exception sınıfı
        if (!file_exists($path)) {
            throw new \Exception("Dosya bulunamadı: {$path}");
        }
        return fopen($path, 'r');
    }
}

Ya da dosyanın üstüne use \Exception; yazabilirsiniz; sonrasında \ olmadan kullanırsınız.

Bu \ öneki birçok kişinin atlayıp hata aldığı yerdir. Namespace içinde Exception yazdığınızda PHP önce App\Services\Exception sınıfını arıyor; bulamayınca hata veriyor. \Exception yazarak “global namespace’deki Exception” diyorsunuz. Aynı durum DateTime, PDO, ArrayObject gibi tüm yerleşik sınıflar için geçerli.

Fonksiyon ve sabit namespace’leri

Sınıfların yanı sıra fonksiyonlar ve sabitler de namespace altında tanımlanabiliyor:

<?php
namespace App\Helpers;

function format_para(float $tutar, string $para_birimi = 'TL'): string
{
    return number_format($tutar, 2, ',', '.') . ' ' . $para_birimi;
}

const MAKSIMUM_DOSYA_BOYUTU = 2048; // KB

Bu fonksiyona ve sabite başka bir dosyadan erişmek için:

<?php
use function App\Helpers\format_para;
use const App\Helpers\MAKSIMUM_DOSYA_BOYUTU;

Ya da tam adıyla: \App\Helpers\format_para(100.0). Fonksiyon ve sabit namespace’leri sınıflara kıyasla daha az kullanılıyor; ama global fonksiyon kirliliğinden kaçınmak için faydalı.

Neden önemli?

Kütüphane kullanmaya başladığımda namespace’in değerini daha iyi anladım. Composer ile kurulan her paketin kendi namespace’i var. Kendi kodunuz da bir namespace altındaysa her şey ayrı katmanda duruyor; hiçbir çakışma yok.

Bunu benimsemeden önce bazen MyProject_User, MyProject_Auth_User gibi öneklerle isim çakışmalarını önlemeye çalışırdım. Bu eski PSR-0 döneminin kalıntısı bir çözümdü; namespace varken buna gerek kalmıyor.

Küçük tek-dosyalı scriptlerde namespace şart değil. Ama birden fazla dosyadan oluşan her projede kullanmakta fayda var. Alışması birkaç proje alıyor; bir kez oturduğunda geriye bakıp “bunu neden daha önce yapmadım” diye soruyorsunuz.

Etiketler: #PHP
Paylaş:

İlgili Yazılar

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi