A PHP sajátossága (volt), hogy mindenki próbálta utánozni a névtereket (namespace), mivel nem álltak rendelkezésünkre. Ennek az volt a következménye, hogy borzasztóan hosszú, igen csúnya osztálynevek születtek:
class Zend_Http_Client_Adapter_Socket
és ez még nem is a legcsúnyábbik.. :)
Az új verzióban viszont már megoldódik ez a probléma, és mint a normálisabb nyelvekben szokás, használhatunk névtereket, amik segítségével lényegében csoportokra, csomagokra oszthatjuk kódunkat, így elkerülvén az egyszerű osztálynevek használatakor gyakran előforduló névütközéseket.
A jövőben, különböző névterekben, használhatjuk ugyan azokat az osztályneveket, mégsem fog tőle kiakadni a fordító.
A névtér meghatározása a fájlunk legelején kell elhelyezkedjen:
<?php namespace MyProject::FirstNamespace; const FIRST_CONST = "first"; function firstFunction(); class FirstClass {} ?>
Fontos tudni, hogy névterekben csak konstansokat, függvényeket és osztályokat definiálhatunk.
Ezek után, ha egy másik névtérben (pl. MyProject::SecondNamespace) csinálunk szintén egy osztályt, aminek a neve FirstClass, semmi probléma... A névtereket a use kulcsszóval tudjuk importálni más névterekbe:
<?php use MyProject::FirstNamespace; $fn = new FirstNamespace::FirstClass(); ?>
Ha nem használjuk a use kulcsszót, akkor is tudunk természetesen hivatkozni az osztályunkra, ebben az esetben az osztály neve elé kell írni a névteret is:
<?php $fn = new MyProject::FirstNamespace::FirstClass(); ?>
Arra is lehetőségünk van, hogy aliasokat használjunk az importált namespace-ekhez:
<?php use MyProject::FirstNamespace as FN; $fn = new FN::FirstClass(); ?>
Illetőleg közvetlenül az osztályunkat is iportálhatjuk:
<?php use MyProject::FirstNamespace::FirstClass; $fn = new FirstClass(); ?>
Amikre ismételten igaz az, hogy aliasokat rendelhetünk hozzájuk :D
(Természetesen a konstansok és a függvények elérése ugyan így működik.)
A mágikus __autoload függvényünk a namespace-ek bevezetésével annyiban módosul, hogy az átadott class név a névteret is magába foglalja:
<?php __autoload($className) { echo $className; // kimenete pl.: MyProject::FirstNamespace::FirstClass } ?>
Jól látható, hogy ennek köszönhetően igen egyszerűen írható egy buta alap autoload, ha a névterek konzisztensek a könyvtárstruktúránkkal, csak a "::"-ot kell lecserélni pl. "/" jelre. (nem látom értelmét a DIRECTORY_SEPARATOR konstans használatának, mivel ez nem lényeges az útvonalak meghatározásában, a "/" jel egyaránt működik windowson és linuxon...
El ne felejtsem új konstansunkat: __NAMESPACE__
Természetesen az aktuális névterünket tárolja.
Amennyiben nem adjuk meg a használandó névteret, osztályunk a globális névtérbe (global scope) fog kerülni, amire úgy hivatkozhatunk, hogy szimplán az osztálynév elé írunk két kettőspontot (::MyClass).
Ha a hivatkozás alkalmával ezt is elhagynánk, akkor a következő utat járja be a fordító:
- megpróbálja megkeresni az osztályt az aktuális névtérben
- megpróbálja megkeresni az osztály a globális névtérben, kikerülve az autoload-ot
- az autoload-hoz fordul segítségért, az aktuális névtérben
ha egyik sem sikerül, az osztályt eltűntnek nyilvánítja.
A névterekről kb ennyit érdemes megemlíteni, ráadásul közben, dolgozó ember lévén rájöttem, hogy jól elment az idő, így a late static binding -ről inkább majd később írok :)
Update
Kitalálták a PHP nagyjai, hogy a separator mégsem a "::" lesz, hanem a "\"... Ezen agyaltak hetekig, és képesek voltak ezt kitalálni. Már én is érzem, hogy a PHP-nak a koporsójába veregetik a szögeket, a kérdés már csak az, hogy még mennyi fér bele. Részemről erősen úgy néz ki a helyzet, hogy ebből JAVA-zas lesz.. PHP, template nyelv...
beleszóltak