Przestrzenie nazw w PHP (namespaces)

Logo PHP7

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