Letscode.hu

… minden ami fejlesztés

De jegyezd meg jól, míg a Föld kerek, mindig lesznek névterek!

2 min read

Tudom, hogy tartozom még mindenféle cikkel, ezért rangsorolnom kell őket, aszerint, hogy épp DiscontinuousNamespacemennyire nagy a baj az adott területen vagy épp mennyire sürgető lenne megismerni olyan dolgokat, amik így 2015-ben a "zalapműveltséghez" tartoznak bizonyos körökben.

A címből gondolom már mindenki rájött, hogy most a Pokolgép zenekar tündöklése és bukása névterek kerülnek terítékre és mindaz, amit használatukkal és bevezetésükkel elérhetünk.

Mi is az a névtér?

Amikor valaki nekiáll programozni és sorban ontja magából az osztályokat, függvényeket, akkor lehet ő is belefutott már abba a problémába, amit névütközésnek nevezünk, miszerint ugyanazon névvel csak egy függvényt/osztályt lehet definiálni (még jó, különben runtime érkezési sorrendben hívódnának meg, mint a háziorvosnál). Ennek a kiküszöbölésére variáljuk a függvényünk nevét kis- és nagybetűkkel, alsóvonásokkal hozták létre még régebben a névterek fogalmát.

Amikor valaki nem használ névtereket, akkor is használja őket, illetve csak egyet, mégpedig a globális névteret, ami minden más névtér felett áll. A namespace-ek (igen, a névtér már kissé uncsi volt) arra szolgálnak, hogy ezt az ütközést elkerüljük és csoportosítsuk, rendszerezzük a kódunkat.

Deklaráljunk hát egy névteret!

<?php
namespace System;
class MeinClass {
}

Fontos megjegyezni, hogy névtereket mindig a fájl elején deklaráljunk, különben nyávogni fog a parser. Ez a névtér az egész fájlra érvényes lesz, ha egy fájlon belül több névtért szeretnénk deklarálni, akkor kapcsos zárójeleket használjunk a következő módon:

namespace System {
class MeinClass {}
}
namespace AnotherNamespace {}

Fentebb deklaráltunk egy System névre hallgató namespace-t és azon belül pedig egy MeinClass osztályt.

Ezt egyazon névtéren belül úgy szimplán a MeinClass névvel tudunk elérni, viszont a névtéren kívülről a System\MeinClass-al, amit úgy hívunk, hogy fully qualified classname.

A globális névtérben deklarált osztályokat és függvényeket (kivéve a beépített függvényeket és eljárásokat) egy \ prefixel tudjuk a névtéren belülről elérni. Vagyis ha a MeinClass-t a globális névtérben deklaráltuk, akkor a System névtéren belülről a \MeinClass-al tudjuk elérni. Erre kivételek hajigálásánál figyeljünk!

Kihasználni a névtereket

A névterek használatával szorosan összefügg a use kulcsszó. A use kulcsszóval tudjuk használatba venni/importálni az adott osztályt, amit a már előbb említett fully qualified classname-el kell megadni, vagyis minden névtér előtaggal együtt. Apropó, a névtereket lehet egymásba ágyazni, ilyen formán csomagokat, modulokat tudunk létrehozni magunk számára.

<?php 
namespace System\Nested\ReallyNested; // több névtért egymásba lehet ágyazni ám!
use OAuth2\Server;  // az OAuth2 névtérben található Server osztályt importáljuk, ami Server-ként érhető el.
use System\MeinClass as Mc; // az előbbi System névtérben található MeinClass-t importáljuk és egy álnévvel látjuk el, így a kód többi részében Mc-ként hivatkozhatunk rá.

Importáláskor az autoloaderjeink (amik ugye vannak?) sietnek segítségünkre és megkapják az osztály nevét, a névterekkel együtt, ám escapelik a stringben szereplő backslash-t, így az autoloader a System\\MeinClass string-et fogja megkapni a fenti esetben.

Ha egy egyszerű autoloadert összedobunk a projektünk gyökerében (ami ugye egy index.php-t tartalmazó public folder felett van egy szinttel, ugye?) és az nemes egyszerűséggel így néz ki:

<?php
define('DS', DIRECTORY_SEPARATOR); oprendszere vállógatja
define('APP_ROOT', __DIR__. DS); // definiáltuk a gyökérkönyvtárat

spl_autoload_register('TestAutoload');

function TestAutoload($className) { // a fully qualified classname-t kapja meg
    $segments = explode("\\", $className);
    if (file_exists(APP_ROOT. implode(DS, $segments) . ".php" )) {
       include_once(APP_ROOT. implode(DS, $segments). ".php"); 
    } 
}

Akkor a System\MeinClass-t a projektgyökere\System\MeinClass.php-ben fogja keresni. Ilyen formában a névtereinket és a könyvtárstruktúránkat szinkronba hozhatjuk.

Ezzel a projektenként újra és újra előforduló kódokat csoportosíthatjuk, csinálhatunk magunknak egyfajta standard library-t és oda gyűjtögethetjük azt. FQC = Fully qualified classname

- Module // az adott modul, netán projekt neve namespace Module;
| - Controller // namespace Module\Controller;
| | - AjaxController.php // FQC Module\Controller\AjaxController;
| | - FrontendController.php // FQC Module\Controller\FrontendController
| - Model // namespace Module\Model;
| | // Nem, ide nem kerülnek modulspecifikus modellek, itt jöhet a trükk
- System // namespace System;
| - Model // namespace System\Model;
| | - UserModel // FQC System\Model\UserModel;
| | - User // FQC System\Model\User
| - Db // namespace System\Db;
| | - DbAdapter // FQC System\Db\DbAdapter;

A view fájlokkal ez esetben nem foglalkozok, vegyük úgy, hogy a routerünk már ott is teremtett bennünket a FrontendControllerünkben.

<?php
namespace Module\Controller; 

use System\Model\UserModel; // importáltuk a UserModelt.
use System\Db\DbAdapter; // importáljuk az adatbázis adaptert

class FrontendController {

   public function indexAction() {
       $um = UserModel::getInstance(); // elérjük a usermodelt 
       $um->setAdapter(new DbAdapter($valamiDbConfig)); // és beállítjuk az adatbázis adaptert rajta
       try {
           $um->commitSuicide();
       catch (\Exception $e) { // \Exception-ként adtuk meg, mivel ha nem írjuk elé, akkor alapesetben az aktuális névtérre vonatkozik, tehát Module\Controller\Exception
           die('die, die my darling!');
       }
   } 

}

A fenti példában és könyvtárszerkezeten remélem jól látszik, hogy valójában mennyire egyszerű és praktikus a névterek használata. Létrehozhatunk portábilis kódrészleteket, amiket ha ugyanazon autoloadereket használunk, a többi projektből is pontosan ugyanúgy érünk el. Viszont vannak a fenti kódban csúnyaságok, ha már a dependency injection-t kitárgyaltam múltkor, de akkor ha több időm és energiám lesz, visszatérek a ServiceLocator-okkal!

3 thoughts on “De jegyezd meg jól, míg a Föld kerek, mindig lesznek névterek!

    1. Köszi, javítva! (Igaz továbbra is DS, hogy rövidebb legyen :D)

  1. Engem mindig érdekelt, hogy miért nem jó a SytemDbAdapter mint osztály elnevezés, ahelyett hogy a SystemDB névtérből vennénk az Adapter osztályt. Szerintem így kevésbé átlátható, hiszen külön meg kell vizsgálnom hogy melyik névtérben vagyok, ahelyett hogy ránéznék az osztály nevére és tudom, hogy melyik az. Talán nem véletlen hogy Te is bent felejtetted azt a Db előtagot az DbAdapternél, biztos ami biztos 🙂

Comments are closed.

Copyright Letscode.hu 2014-2020 © Minden jog fenntartva. | Newsphere by AF themes.