NNPlaya.pl

Ostatnie prace

Przestrzenie nazw w PHP

PHP

Ostatnia stabilna wersja PHP (5.3) przyniosła parę nowości. Dostaliśmy do dyspozycji między innymi funkcje anonimowe oraz przestrzenie nazw. Tym ostatnim poświęciłem niniejszy artykuł, opisując ich użycie w naszych aplikacjach.

Czym są przestrzenie nazw i czemu służą?

Kiedy w swoim projekcie wykorzystujemy kod innych programistów bez jego doskonałej znajomości istnieje ryzyko, że w naszym kodzie wystąpią dwie klasy, dwie funkcje lub chociażby dwie stałe o takiej samej nazwie. Czym to poskutkuje, wiadomo - parser PHP zakończy pracę błędem. Z możliwością wystąpienia takiej sytuacji mamy do czynienia również podczas pracy nad każdym dużym projektem. Aby temu zaradzić, wymyślono przestrzenie nazw. W praktyce są to specjalne przedrostki 'doklejane' na początku nazw klas, funkcji, tudzież stałych. Jeśli programowałeś np. w C++, z pewnością miałeś z nimi do czynienia.

Deklarowanie przestrzeni nazw w PHP i ich zakres ważności

Aby zadeklarować, że od tego momentu wszystkie definicje klas, funkcji oraz stałych należą do danej przestrzeni nazw, należy użyć następującej konstrukcji języka:

namespace mojaPrzestrzenNazw;

Tak zadeklarowana przestrzeń nazw obowiązuje od momentu wystąpienia do końca bieżącego pliku lub do napotkania kolejnej deklaracji. Przykład:

namespace mojaPrzestrzen;
class Punkt {
   private $_coordinateX;
   private $_coordinateY;

   function __contruct($x, $y) {
      $this -> _coordinateX = $x;
      $this -> _coordinateY = $y;
   }
}

$mojPunkt = new Punkt(1,5);

namespace twojaPrzestrzen;

$twojPunkt = new mojaPrzestrzen\Punkt(2, 5);

$twojaKopiaMojegoPunktu = clone $mojPunkt;

Jak widzimy na powyższym listingu, w przestrzeni nazw mojaPrzestrzen zdefiniowano klasę Punkt oraz utworzono jej instancję przypisaną do zmiennej $mojPunkt. Następnie zdefiniowano kolejną przestrzeń (twojaPrzestrzen) i zgodnie z tym, co napisałem powyżej, zakres ważności mojejPrzestrzeni przestał obowiązywać. Teraz odwołano się do klasy Punkt ponownie tworząc jej instancję. Należy zwrócić uwagę, w jaki sposób 'pokonano' barierę istnienia definicji klasy w innej przestrzeni nazw

...
$twojPunkt = new mojaPrzestrzen\Punkt(2, 5);
...

Jak zauważamy, zasięg zmiennych nie ogranicza się do przestrzeni nazw, w których zostały zdefiniowane. Dlatego bez problemu możemy się odwołać do zmiennej $mojPunkt w przestrzeni twojaPrzestrzen.

Należy pamiętać, że używanie kilku przestrzeni nazw w jednym pliku jest niezalecane.

Odwoływanie się do przestrzeni globalnej

Aby wewnątrz pewnej przestrzeni wywołać funkcję, która została zdefiniowana poza jakąkolwiek przestrzenią nazw, należy poprzedzić jej nazwę pojedynczym znakiem '\' (backslash). Przykład:

function jakasFunkcja() { /* */}

namespace mojaPrzestrzen;

echo \jakasFunkcja();

A jak powrócić do globalnego zakresu? Należy zdefiniować przestrzeń nazw nie podając jej nazwy i dodatkowo korzystając z alternatywnej składni, używając nawiasów klamrowych:

namespace mojaPrzestrzen {

   const mojaStala = 1;

}
namespace {

   echo mojaPrzestrzen\mojaStala;

}

Oczywiście z tej składni można korzystać również bez 'powracania' do przestrzeni globalnej:

namespace mojaPrzestrzen {
   /* ...  */
}
namespace twojaPrzestrzen {
   /* ... */
}

W jednym pliku nie wolno mieszać składni używającej nawiasów klamrowych oraz klasycznej.

Definiowanie podrzędnych przestrzeni nazw

Do tego celu wystarczy oddzielać kolejne człony nazwy znakiem backslasha. Przykład (z php.net):

namespace MyProject\Sub\Level;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */  }
[p]Powyższy przykład tworzy stałą MyProject\Sub\Level\CONNECT_OK, klasę MyProject\Sub\Level\Connection oraz funkcję MyProject\Sub\Level\connect

Stała predefiniowana __NAMESPACE__

Ta stała zawiera w sobie nazwę bieżącej przestrzeni nazw.

namespace mojaPrzestrzen {

   echo __NAMESPACE__;

}
namespace {
   echo __NAMESPACE__;
}

Co dziwić nie powinno, pierwsza instrukcja echo wyświetli nam ciąg 'mojaPrzestrzen', zaś druga pustą zmienną typu string.

Słowo kluczowe namespace

Oprócz definiowania przestrzeni nazw, słowo namespace może być używane jako operator odwołujący się do bieżącej przestrzeni, swoisty odpowiednik self:: z klas. Przykład:

namespace mojaPrzestrzen;
namespace\przestrzenPodrzedna\jaksFunkcja(); // Wywołuje funkcję mojaPrzestrzen\przestrzenPodrzedna\jakasFunkcja();

A jak zachowuje się operator namespace w globalnej przestrzeni nazw?

namespace\mojaKlasa::statycznaMetoda(); //Wywołuje statyczną metodę klasy mojaKlasa zdefiniowanej w globalnej przestrzeni nazw.

Zakończenie

W powyższym tekście postarałem się przybliżyć wstępnie zagadnienie przestrzeni nazw w PHP. Prawdopodobnie przez sporą część programistów przestrzenie zostaną uznane za niepotrzebną innowację, niemniej jednak są warte uwagi. Po więcej informacji odsyłam do manuala.

4 komentarze »
#1 by MWL 10 września 2009 o godzinie 13:21 O tym nie wiedziałem :) Fajny artykuł. Gratuluję.
#2 by TeMPOraL 10 września 2009 o godzinie 13:29 No nareszcie :). Przez cały czas w PHP najbardziej brakowało mi właśnie przestrzeni nazw. Niby zawsze dało się to obejść pisaniem odpowiednich przedrostków przed wszystkimi klasami, funkcjami - robili tak nawet co mądrzejsi programiści w C - ale ta metoda jest mimo wszystko bardzo niewygodna. Troszkę tylko boli mnie składnia ze znaczkiem \ - moim zdaniem C++ ma to rozwiązane najlepiej, z operatorem zakresu (operator :: ).
#3 by NNPlaya 10 września 2009 o godzinie 13:37 Również chętniej widziałbym operator Paamayim Nekudotayim (notabene podwójny dwukropek po hebrajsku, przepraszam za koszmarną nazwę, ale taka widnieje w manualu PHP). :P
#4 by radex 14 grudnia 2009 o godzinie 23:28 no ja się trochę rozczarowałem z namespaces w PHP... Ale i tak z nich pewnie będę korzystał w większych projektach, bo to po prostu jest bardzo przydatne. PS. Zawsze zastanawiałem się skąd wzięli to Paamayim Nukedotayim, a to z hebrajskiego :D