Definir un espacio de nombres
Si no se indica lo contrario, todas las clases y funciones serán definidas en un entorno global. Con la posibilidad de que haya las colisiones de nombres comentadas anteriormente. Así que vamos a empezar a definir un espacio de nombres. Para definir uno, simplemente tenemos que utilizar la palabra reservada namespace seguida del nombre identificador del espacio de nombres. Además la definición de un espacio de nombres es lo primero que tiene que aparecer en el script. Posteriormente ya se pueden hacer los 'includes' necesarios.
Lo habitual es definir un espacio de nombres por script, declarándolo al principio del mismo. Sin embargo es posible definir varios de ellos en un mismo script.
namespace primer;
class Test{
}
class Prueba{
}
namespace segundo;
class Test{
}
Hay que tener en cuenta que el contenido de los diferentes espacios de nombres, diferentes definidos en un mismo script, se puede introducir entre corchetes. Pero no se pueden mezclar espacios de nombres con corchetes y otros sin ellos. En caso contrario se mostrará el siguiente error:
Fatal error: Cannot mix bracketed namespace declarations with unbracketed namespace declarations in...
namespace Test{
class Prueba {
public function __construct() {
}
}
}
namespace Test2 {
class Prueba {
public function __construct() {
}
}
}
Si queremos una mejor organización de las clases, podemos crear una organización jerárquica con los nombres de espacios. Ya que podemos anidar espacios de nombres. Para ello simplemente utilizaremos la barra invertida '\' para separar sub-espacios de nombres.
<?php
namespace MyProyecto\Espacio1;
class Database{
}
class Usuario{
}
?>
<?php
namespace MyProyecto\Espacio2;
class Articulo{
}
?>
<?php
namespace MyProyecto\Utiles;
class Debug{
}
?>
De la misma forma que se ha visto anteriormente, podemos definir sub-espacios de nombres en un mismo script.
Hemos comentado, que si no indicamos ningún espacio de nombres, el código pertenecerá al espacio de nombres global. Ahora bien, tenemos la posibilidad de que una parte del script definido con un espacio de nombres concreto pertenezca al espacio de nombres global. Para ello usaremos la palabra reservada namespace sin nombre identificador. Y encerraremos el código de cada espacio de nombres, el definido y el global, entre corchetes:
<?php
namespace Prueba\Ejemplo{
class Test{
}
function prueba(){
}
}
namespace{
class Coche{
}
}
Acceder a un espacio de nombres
Dependiendo de nuestra posición (espacio de nombres actual) en la aplicación, hay 3 formas diferentes de acceder al nombre de una clase o función definida en un espacio de nombres. Imaginemos que en el espacio de nombres Proyecto\Blog\Admin esta definida la clase Usuario.
ejemplo.php
<?php
namespace Proyecto\Blog\Admin;
class Usuario{
private $nombre;
function getNombre(){
return $this->nombre;
}
function setNombre($name){
$this->nombre = $name;
}
}
?>
1. Si queremos utilizar las clase Usuario y si estamos en un espacio de nombres que no está dentro de la jerarquía que contiene dicha clase, necesitamos utilizar la jerarquía completa para poder acceder a ella. A esta forma se le llama nombre completamente cualificado. Y es análogo a utilizar una ruta absoluta en un sistema de ficheros.
<?php
namespace Prueba;
include './ejemplo.php';
$usuario = new \Proyecto\Blog\Admin\Usuario();
var_dump($usuario);
?>
Recuerda que si estamos en un espacio de nombres particular pero utilizamos namespace sin nombre identificador seguido de corchetes, estamos accediendo al espacio de nombres global.
<?php
namespace Prueba{
include './ejemplo.php';
//...
}
namespace{
$usuario = new \Proyecto\Blog\Admin\Usuario();
}
?>
Si queremos utilizar una función del espacio de nombres global y esta se llama del mismo modo que una de las definidas en el espacio de nombres actual, usaremos un nombre completamente cualificado. Recuerda que el primer '\' representa el inicio en la jerarquía.
namespace Prueba;
function strlen($cadena) {
echo $cadena . "<br/>";
}
echo strlen('hola'); // llama a la función strlen del namespace actual
echo \strlen('hola'); // llama a la función global strlen
Si no hay conflictos de nombres, para acceder a la función del espacio de nombres global, no será necesario ninguna referencia a ningún espacio de nombres.
namespace Prueba;
function strlen_prueba($cadena) {
echo $cadena . "<br/>";
}
echo strlen('hola');
2. Si estamos dentro de algún nivel en la jerarquía que contiene a la clase solicitada, no necesitamos utilizar la ruta completa si no que utilizaremos una ruta relativa al espacio de nombres en el que nos encontremos. A esta forma de acceso se le llama nombre cualificado.
namespace Proyecto\Blog;
include './namespaces.php';
$usuario = new Admin\Usuario();
var_dump($usuario);
3. Si estamos en el espacio de nombres actual, utilizamos la clase como siempre la habíamos utilizado hasta ahora, sin hacer referencia a ningún espacio de nombres. A esta forma de acceso se le llama nombre no cualificado.
namespace Proyecto\Blog\Admin;
include './namespaces.php';
$usuario = new Usuario();
var_dump($usuario);
Importando un espacio de nombres
Como hemos explicado anteriormente, si estamos en un 'namespace' ajeno jerárquicamente al
al que necesitamos, podemos utilizar un nombre completamente cualificado para acceder a una clase de dicho espacio de nombres.
<?php
namespace Prueba;
require './ejemplo.php';//script con definición de clase Usuario
$usuario = new \Proyecto\Blog\Admin\Usuario();
var_dump($usuario);
?>
Pero de esta forma, si en nuestro ejemplo tenemos que instanciar numerosas veces a la clase Usuario, tenemos que escribir toda la jerarquía: new \Proyecto\Blog\Admin\Usuario() numerosas veces. Esto es muy incomodo y por eso los espacios de nombres permiten su importación.
Para importar un espacio de nombres se utiliza la palabra reservada use, seguida del espacio de nombres a importar.
<?php
namespace Prueba;
require './ejemplo.php';
use Proyecto\Blog\Admin;
$usuario = Admin\Usuario();
var_dump($usuario);
?>
La utilización del comando use no cambia el espacio en el que trabajamos. Simplemente nos permitirá utilizar implementaciones de otros espacios de nombres haciendo uso del nombre cualificado (ruta relativa). Sin importar un espacio de nombre, utilizábamos un nombre completamente cualificado (ruta absoluta).
En un script se pueden importar tantos espacios de nombres como se quieran.
Alias de un espacio de nombres
Además de importar un espacio de nombres, podemos utilizar un alias del mismo para acortar las llamadas a los recursos. Para ello utilizaremos la palabra reservada as tras la importanción del espacio de nombres:
use espacioDeNombresImportar as alias;
namespace Prueba;
require './namespaces.php';
use Proyecto\Blog\Admin as Ad;
$usuario = new Ad\Usuario();
var_dump($usuario);
Pero si queremos evitar tener que llamar la ruta relativa desde el alias, podemos optar por importar directamente la clase. Y si queremos le aplicaremos un alias.
namespace Prueba;
require './namespaces.php';
use Proyecto\Blog\Admin\Usuario;
$usuario = new Usuario();
var_dump($usuario);
namespace Prueba;
require './namespaces.php';
use Proyecto\Blog\Admin\Usuario as clase;
$usuario = new clase();
var_dump($usuario);
__NAMESPACE__ y namespace
La constante __NAMESPACE__ contiene el nombre del espacio de nombres actual. Si el espacio de nombres actual es el global, la constante devolverá una cadena vacía.
namespace Prueba {
require './namespaces.php';
use Proyecto\Blog\Admin\Usuario as clase;
echo __NAMESPACE__ . "<br/>"; //Prueba
}
namespace {
if (__NAMESPACE__ == "") echo "Espacio de nombres global";
}
Los principales usos:
- Tareas de depuración de los scripts.
- Construcción de nombres completamente cualificados de forma dinámica.
La palabra reservada namespace, aparte de usarse para definir espacios de nombres, también puede ser usada para solicitar un recurso, de forma explicita, del espacio de nombres actual o de un espacio de nombres hijo.
namespace Test {
class Prueba {
public function __construct() {
echo __NAMESPACE__;
}
}
}
namespace Test2 {
class Prueba {
public function __construct() {
echo __NAMESPACE__;
}
}
$p = new namespace\Prueba();//Test2
}
Espacios de nombres y la autocarga
Como explicamos en el tutorial de la función mágica de autocarga, para evitar tener que hacer todas las inclusiones de los scripts para poder hacer uso de los recursos definidos en ellos, podemos hacer uso de esta función que intentará realizar la inclusión del recurso que necesitemos.
$obj1 = new Usuario(); // class/Usuario.php autocargada
$obj2 = new Usuario2(); // class/Usuario2.php autocargada
function __autoload($nombre_clase)
{
require_once 'class/' . $nombre_clase. '.php';
}
Usar la función de autocarga de este modo implica colocar todas las clases en un directorio. A no ser que se quiera complicar mucho su implementación. Pero gracias a los espacios de nombres se podría optar por organizar la estructura de ficheros (scripts) de la misma forma que la estructura de espacios de nombres de la aplicación. Ya que mediante los espacios de nombres podemos pasar a la función mágica un nombre completamente cualificado y el nombre de una clase. Por ejemplo, en nuestro anterior función mágica $nombre_clase podría ser 'Proyecto\Blog\Admin\Usuario. Y dentro de la función convertir la ruta del espacio de nombres en una ruta de ficheros. Vamos a ver un ejemplo.
class/Proyecto/Blog/Admin/Usuario.php
namespace Proyecto\Blog\Admin;
class Usuario{
private $nombre;
function getNombre(){
return $this->nombre;
}
function setNombre($name){
$this->nombre = $name;
}
}
app.php
use Proyecto\Blog\Admin\Usuario as usr;
$usuario = new usr();
$usuario->setNombre('Jose');
echo $usuario->getNombre() . "<br/>";
function __autoload($nombre_clase) {
echo $nombre_clase;//Proyecto\Blog\Admin\Usuario
// convertimos espacio de nombres en ruta completa de ficheros
$clase = 'class/' . str_replace('\\', '/', $nombre_clase) . '.php';
echo "ruta clase: " . $clase . "<br/>";// class/Proyecto/Blog/Admin/Usuario.php
require_once($clase);
}
Entradas relacionadas
PHP orientado a objetos - Introducción
No hay comentarios:
Publicar un comentario