Import, alias, dan nama absolut adalah alat tulis yang kita pegang; resolusi nama adalah mesin yang bekerja di balik layar setiap kali interpreter membaca simbol apa pun. Memahami mesin tersebut membuat kita bisa memprediksi nama apa yang sebenarnya dicari PHP, membaca pesan galat dengan tepat, dan menghindari jebakan klasik seperti class bawaan yang tidak ditemukan. Pada chapter ini kita merangkum aturan resolusi secara sistematis: tiga bentuk nama, perbedaan perlakuan antara class dan function, serta kelakuan khusus untuk nama yang dibangun secara dinamis.

Tiga Bentuk Nama dan Aturan Resolusinya #

Setiap nama class, function, atau constant yang kita tulis selalu termasuk salah satu dari tiga bentuk berikut:

BentukContohCara interpreter membacanya
Unqualified (tanpa backslash)Koneksidigabung dengan namespace saat ini
Qualified (berpemisah \, tanpa backslash awal)Admin\Koneksiseluruh nama digabung dengan namespace saat ini
Fully qualified (diawali \)\App\Models\Koneksidibaca absolut dari namespace global

Tabel di atas berlaku mutlak untuk class; function dan constant mendapat satu kelonggaran ekstra yang kita bahas pada dua bagian berikutnya. Contoh berikut memperlihatkan ketiga bentuk tersebut bekerja pada nama class Koneksi:

php
<?php
namespace App\Models {
    class Koneksi {}
}

namespace App\Models\Admin {
    class Koneksi {}

    $a = new Koneksi();
    $b = new \App\Models\Koneksi();

    echo get_class($a), "\n";
    echo get_class($b), "\n";
}

namespace App\Models {
    $c = new Admin\Koneksi();

    echo get_class($c), "\n";
}

Output yang Dihasilkan:

text
App\Models\Admin\Koneksi
App\Models\Koneksi
App\Models\Admin\Koneksi

Mari kita telaah ketiga baris pentingnya:

  1. new Koneksi() di dalam App\Models\Admin: nama unqualified menerima prefix App\Models\Admin, sehingga class yang terpilih adalah App\Models\Admin\Koneksi.
  2. new \App\Models\Koneksi(): nama fully qualified dibaca absolut, dan class di namespace App\Models yang terpilih meskipun kode berada satu tingkat lebih dalam.
  3. new Admin\Koneksi() di dalam App\Models: nama qualified digabung dengan App\Models, menghasilkan App\Models\Admin\Koneksi — sama seperti hasil poin pertama dari posisi yang berbeda.

Class Tidak Pernah Jatuh ke Namespace Global #

Untuk class, aturannya keras: nama unqualified dan qualified hanya dicoba dengan prefix namespace saat ini. Jika class dengan nama hasil penggabungan itu tidak ada, PHP langsung melempar Error — tidak pernah ada pencarian kedua di namespace global. Contoh klasiknya adalah memakai class bawaan DateTimeImmutable tanpa import dan tanpa backslash awal:

php
<?php
namespace App\Util;

$tanggal = new DateTimeImmutable("2026-01-15 08:00:00");
echo $tanggal->format("Y-m-d H:i:s"), "\n";

Output yang Dihasilkan:

text

Fatal error: Uncaught Error: Class "App\Util\DateTimeImmutable" not found in /home/z/my-project/php-course/content/php/namespaces-dan-autoloading/namespace-resolution/.verify_tmp.php:4
Stack trace:
#0 {main}
  thrown in /home/z/my-project/php-course/content/php/namespaces-dan-autoloading/namespace-resolution/.verify_tmp.php on line 4

Pesan galatnya menyebut Class "App\Util\DateTimeImmutable" not found — bukti bahwa interpreter menempelkan prefix App\Util pada nama yang kita tulis, lalu berhenti begitu nama itu tidak ditemukan. Namespace global tempat DateTimeImmutable yang asli tinggal tidak pernah dikunjungi. Dua jalan keluarnya sudah kita kenal: import dengan use, atau tulis nama absolut \DateTimeImmutable.

Function dan Constant Bisa Jatuh ke Global #

Function dan constant unqualified mendapat kelonggaran yang tidak dimiliki class: jika tidak ditemukan di namespace saat ini, PHP mencoba sekali lagi di namespace global. Perhatikan contoh berikut yang mencampur simbol lokal dan simbol global.

php
<?php
namespace App\Util;

function strlen(string $teks): int
{
    return 42;
}

echo strlen("PHP"), "\n";
echo strtoupper("php"), "\n";
echo PHP_INT_MAX, "\n";

Output yang Dihasilkan:

text
42
PHP
9223372036854775807

Berikut penjelasan ketiga hasilnya:

  1. strlen("PHP"): function App\Util\strlen ditemukan lebih dahulu, sehingga versi lokal yang mengembalikan 42 yang menang — fallback tidak pernah dijalankan.
  2. strtoupper("php"): App\Util\strtoupper tidak ada, pencarian dijatuhkan ke function global, dan hasilnya PHP.
  3. PHP_INT_MAX: constant ini tidak didefinisikan di App\Util, sehingga nilainya diambil dari constant global milik PHP.

Batasan Fallback pada Nama Qualified #

Kelonggaran fallback hanya berlaku untuk nama unqualified. Begitu sebuah nama function memuat pemisah backslash, nama tersebut dianggap qualified dan dibaca strictly relatif terhadap namespace saat ini — global tidak pernah dicoba. Contoh berikut membuktikannya dengan sebuah function global bernama muatKonfigurasi:

php
<?php
namespace {
    function muatKonfigurasi(): string
    {
        return "konfigurasi global";
    }
}

namespace Aplikasi {
    echo \muatKonfigurasi(), "\n";
    echo muatKonfigurasi(), "\n";
    echo Admin\muatKonfigurasi(), "\n";
}

Output yang Dihasilkan:

text
konfigurasi global
konfigurasi global

Fatal error: Uncaught Error: Call to undefined function Aplikasi\Admin\muatKonfigurasi() in /home/z/my-project/php-course/content/php/namespaces-dan-autoloading/namespace-resolution/.verify_tmp.php:12
Stack trace:
#0 {main}
  thrown in /home/z/my-project/php-course/content/php/namespaces-dan-autoloading/namespace-resolution/.verify_tmp.php on line 12

Dua baris pertama berhasil: bentuk absolut \muatKonfigurasi() langsung menemukan function global, dan bentuk unqualified muatKonfigurasi() dijatuhkan ke global setelah Aplikasi\muatKonfigurasi tidak ditemukan. Baris ketiga gagal fatal: Admin\muatKonfigurasi() dihitung sebagai Aplikasi\Admin\muatKonfigurasi, dan karena nama qualified tidak mendapat fallback, PHP melempar Call to undefined function meskipun muatKonfigurasi global nyata ada.

Nama Dinamis Selalu Diperlakukan Absolut #

Import dan alias adalah informasi kompilasi; nama yang dibangun secara dinamis — lewat variable pada new $nama atau string yang dilempar ke class_exists() — tidak pernah melalui mesin tersebut. String apa pun dianggap nama fully qualified, sehingga prefix namespace saat ini tidak pernah ditempelkan secara otomatis.

php
<?php
namespace App\Models {
    class Pengguna {}
}

namespace Aplikasi {
    $namaClass = "App\Models\Pengguna";

    $pengguna = new $namaClass();
    echo get_class($pengguna), "\n";

    var_dump(class_exists("Pengguna"));
}

Output yang Dihasilkan:

text
App\Models\Pengguna
bool(false)

Pada baris new $namaClass(), variable berisi nama lengkap App\Models\Pengguna sehingga instansiasi berhasil dan get_class() mencetak nama tersebut. Sebaliknya, class_exists("Pengguna") mencari class bernama Pengguna di namespace global — perhatikan, bukan Aplikasi\Pengguna — dan mengembalikan false meskipun App\Models\Pengguna sudah terdefinisi di berkas yang sama.

Ringkasan #

  • Nama unqualified dan qualified digabung dengan namespace saat ini; nama fully qualified dibaca absolut.
  • Class hanya dicari dengan prefix namespace saat ini — tanpa fallback — sehingga class bawaan PHP wajib di-import atau ditulis absolut.
  • Function dan constant unqualified dijatuhkan ke namespace global bila tidak ditemukan; nama qualified dan fully qualified tidak mendapat perlakuan itu.
  • Nama yang dibangun secara dinamis selalu dianggap fully qualified, apa pun namespace yang mengelilinginya.

Aturan resolusi menjelaskan mengapa pesan galat kadang menampilkan nama yang tidak pernah kita tulis. Pertanyaan terakhir yang tersisa: class yang belum terdefinisi harus dibuat nyata dengan cara apa sebelum dipakai? Jawabannya adalah autoloading — mekanisme yang memuat definisi class tepat pada saat dibutuhkan — dan itulah pokok bahasan chapter berikutnya.

Referensi #