W tym wpisie wyjaśnię co to są przestrzenie nazw (ang. namespaces) używane zarówno w PHP, jak i w wielu innych językach programowania.
Wiele funkcji w PHP korzysta z domyślnej przestrzeni nazw. Wystarczy, że wpiszemy w kodzie strip_tags(), echo(), print() i dana funkcja zostanie wykonana. W przestrzeni globalnej możemy tworzyć także swoje funkcje, zmienne i klasy.
Załóżmy, że chcemy stworzyć klasę MojaKlasa w pliku classes/MojaKlasa.php
Tworzymy plik w katalogu /classes/MojaKlasa.php i dodajemy do niego następującą przykładową stałą i klasę:
<?php const MYCONST = 'classes/MojaKlasa.php'; class mojaKlasa{ public static function Test(){ return 'test funkcji'; } }
Plik ten dołączamy do głównego pliku naszego projektu (w głównym katalogu) o nazwie index.php, oto jego zawartość:
<?php require_once(__DIR__.'/classes/MojaKlasa.php'); echo MYCONST; echo MojaKlasa::Test();
Po otworzeniu na serwerze pliku index.php zobaczmy na ekranie komunikat:
classes/MojaKlasa.php test funkcji
W tym przykładzie nie została zadeklarowana żadna przestrzeń nazw, a więc ta klasa i stała jest dostępna w przestrzeni globalnej.
A co w przypadku gdy nasz projekt się rozrasta i z jakiegoś powodu musimy dodać inną klasę lub stałą o takiej samej nazwie?
Skopiujmy nasz katalog classes i zmieńmy jego nazwę na classes_outer.
Następnie w pliku index.php dodajmy odwołanie do nowej klasy:
require_once(__DIR__.'/classes_outer/MojaKlasa.php');
Po odświeżeniu strony w przeglądarce dostaniemy komunikat w stylu: ” Cannot declare class mojaKlasa, because the name is already in use”.
Przestrzeń nazw (namespace)
W tym przypadku użyteczne będą przestrzenie nazw. Aby je stworzyć na samym początku pliku z klasą należy dodać wyrażenie:
namespace NAZWA_PRZESTRZENI;
Deklaracja ta powinna być na samym początku pliku. Cały kod pliku znajdujący się za nią będzie należał do danej przestrzeni nazw. W jednym pliku PHP możemy zadeklarować kilka przestrzeni w ten sposób:
<?php namespace Przestrzen1; // blok kodu dla Przestrzen1 namespace Przestrzen2; // blok kodu dla Przestrzen2 namespace Przestrzen3; // blok kodu dla Przestrzen3
Jednak nie jest to polecane.
Często stosowanym rozwiązaniem jest nadawanie przestrzeni nazw wg lokalizacji danego pliku, czyli np. dla pliku classes/users/actions/register.php będzie to MyApp\Users\Actions\Register
Wróćmy do naszego przykładu. Zmodyfikujmy plik classes_outer/MojaKlasa.php
<?php namespace outer; const MYCONST = 'classes_outer/MojaKlasa.php'; class mojaKlasa{ static public function Test(){ return 'test funkcji w innej klasie'; } }
Dodaliśmy przestrzeń nazw:
namespace outer;
Spróbujmy otworzyć plik index.php w przeglądarce. Tym razem nie wyświetla się żaden błąd. Widzimy, że komunikaty pochodzą z pierwszej dodanej klasy z pliku classes/MojaKlasa.php
Załóżmy, że chcemy teraz użyć drugiej klasy. W tym celu zmodyfikujmy plik index.php
<?php require_once(__DIR__.'/classes/MojaKlasa.php'); require_once(__DIR__.'/classes_outer/MojaKlasa.php'); echo outer\MYCONST; echo('<br>'); echo outer\MojaKlasa::Test();
Po odświeżeniu strony w przeglądarce zobaczymy, że zostały teraz wykorzystane wartości z pliku classes_outer/MojaKlasa.php
Co zostało zmienione? Wywołując stałą oraz klasę dodaliśmy wyrażenie outer\
Powoduje ono, że skrypt będzie szukał tej stałej i klasy nie w zakresie globalnym ale w danej przestrzeni nazw.
Metoda use
Mamy do dyspozycji także metodę use dzięki której nie musimy za każdym razem pisać przestrzeni nazw, wystarczy raz ją zadeklarować:
use outer;
Dyrektywa ta zacznie obowiązywać od miejsca użycia jej w kodzie. Możliwe jest zadeklarowanie używania naraz kilku różnych przestrzeni nazw w ten sposób:
use przestrzen1, przestrzen2, przestrzen3;
Aliasy nazw
Kolejne udogodnienie to tzw. aliasy nazw. Wróćmy do przykładu z przestrzenią nazw MyApp\Users\Actions\Register
Chcąc wykorzystać ją w kodzie, musimy użyć dość długiego wyrażenia np:
$user = new MyApp\Users\Actions\Register\User;
Korzystając z aliasu nazw możemy dodać:
use MyApp\Users\Actions\Register\User as U;
Od tej chwili możemy używać w kodzie formy:
$user = new U;
Podsumowanie
Jak widzicie, przestrzenie nazw to nic skomplikowanego, a naprawdę mogą pomóc utrzymać nasz kod w porządku.
Kod przykładu jest dostępny na GitHub: https://github.com/kamilwyremski/namespaces