# 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.

- Yayın: 2014-04-06
- Kategori: Diller
- Etiketler: PHP
- Okuma süresi: 3 dk okuma
- Kaynak: https://www.muhammetsafak.com.tr/blog/phpde-namespace-ile-kodu-duzenli-tutmak/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
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](/blog/composera-gecis-php-bagimliliklarini-elle-yonetmeyi-birakmak) ve [PSR standartlarıyla](/blog/psr-4-ve-otomatik-yukleme-include-zincirinden-kurtulmak) birlikte yaygınlaştı.

## Temel kullanım

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

```php
<?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
<?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
<?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
<?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
<?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
<?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
<?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.
