Espacios de nombres y características dinámicas del lenguaje

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

La implementación de PHP de los espacios de nombres está influenciada por su naturaleza dinámica como lenguaje de programación. Así, para convertir código como el del siguiente ejemplo en código de espacios de nombres:

Ejemplo #1 Acceder dinámicamente a elementos

ejemplo1.php:

<?php
class nombre_clase
{
function
__construct()
{
echo
__METHOD__,"\n";
}
}
function
nombre_func()
{
echo
__FUNCTION__,"\n";
}
const
nombre_const = "global";

$a = 'nombre_clase';
$obj = new $a; // imprime nombre_clase::__construct
$b = 'nombre_func';
$b(); // imprime nombre_func
echo constant('nombre_const'), "\n"; // imprime global
?>
se debe emplear el nombre completamente cualificado (nombre de clase con prefijo de espacio de nombres). Observe que, debido a que no hay diferencia entre un nombre cualificado y uno completamente cualificado dentro de un nombre de clase, función, o constante dinámicas, no es necesario la barra invertida inicial.

Ejemplo #2 Acceder dinámicamente a elementos de un espacio de nombres

<?php
namespace nombre_espacio_de_nombres;
class
nombre_clase
{
function
__construct()
{
echo
__METHOD__,"\n";
}
}
function
nombre_func()
{
echo
__FUNCTION__,"\n";
}
const
nombre_const = "de espacio de nombres";

/* observe que si se emplean comillas dobles, se debe usar "\\nombre_espacio_de_nombres\\nombre_clase" */
$a = '\nombre_espacio_de_nombres\nombre_clase';
$obj = new $a; // imprime nombre_espacio_de_nombres\nombre_clase::__construct
$a = 'nombre_espacio_de_nombres\nombre_clase';
$obj = new $a; // también imprime nombre_espacio_de_nombres\nombre_clase::__construct
$b = 'nombre_espacio_de_nombres\nombre_func';
$b(); // imprime nombre_espacio_de_nombres\nombre_func
$b = '\nombre_espacio_de_nombres\nombre_func';
$b(); // también imprime nombre_espacio_de_nombres\nombre_func
echo constant('\nombre_espacio_de_nombres\nombre_const'), "\n"; // imprime de espacio de nombres
echo constant('nombre_espacio_de_nombres\nombre_const'), "\n"; // también imprime de espacio de nombres
?>

Asegúrese de leer la nota sobre escapar nombres de espacios de nombres en cadenas.

add a note add a note

User Contributed Notes 7 notes

up
70
Alexander Kirk
12 years ago
When extending a class from another namespace that should instantiate a class from within the current namespace, you need to pass on the namespace.

<?php // File1.php
namespace foo;
class
A {
    public function
factory() {
        return new
C;
    }
}
class
C {
    public function
tell() {
        echo
"foo";
    }
}
?>

<?php // File2.php
namespace bar;
class
B extends \foo\A {}
class
C {
    public function
tell() {
        echo
"bar";
    }
}
?>

<?php
include "File1.php";
include
"File2.php";
$b = new bar\B;
$c = $b->factory();
$c->tell(); // "foo" but you want "bar"
?>

You need to do it like this:

When extending a class from another namespace that should instantiate a class from within the current namespace, you need to pass on the namespace.

<?php // File1.php
namespace foo;
class
A {
    protected
$namespace = __NAMESPACE__;
    public function
factory() {
       
$c = $this->namespace . '\C';
        return new
$c;
    }
}
class
C {
    public function
tell() {
        echo
"foo";
    }
}
?>

<?php // File2.php
namespace bar;
class
B extends \foo\A {
    protected
$namespace = __NAMESPACE__;
}
class
C {
    public function
tell() {
        echo
"bar";
    }
}
?>

<?php
include "File1.php";
include
"File2.php";
$b = new bar\B;
$c = $b->factory();
$c->tell(); // "bar"
?>

(it seems that the namespace-backslashes are stripped from the source code in the preview, maybe it works in the main view. If not: fooA was written as \foo\A and barB as bar\B)
up
4
Daan
4 years ago
Important to know is that you need to use the *fully qualified name* in a dynamic class name. Here is an example that emphasizes the difference between a dynamic class name and a normal class name.

<?php
namespace namespacename\foo;

class
classname     
{                                                                                       
    function
__construct()                                                              
    {                                                                                   
        echo
'bar';
    }                                                                                   
}                                                                                       

$a = '\namespacename\foo\classname'; // Works, is fully qualified name                  
$b = 'namespacename\foo\classname'; // Works, is treated as it was with a prefixed "\"  
$c = 'foo\classname'; // Will not work, it should be the fully qualified name           

// Use dynamic class name                                                                                        
new $a; // bar
new $b; // bar
new $c; // [500]: / - Uncaught Error: Class 'foo\classname' not found in

// Use normal class name                                                                                        
new \namespacename\foo\classname; // bar
new namespacename\foo\classname; // [500]: / - Uncaught Error: Class 'namespacename\foo\namespacename\foo\classname' not found
new foo\classname; // [500]: / - Uncaught Error: Class 'namespacename\foo\foo\classname' not found
up
3
museyib dot e at gmail dot com
5 years ago
Be careful when using dynamic accessing namespaced elements. If you use double-quote backslashes will be parsed as escape character.

<?php
    $a
="\namespacename\classname"; //Invalid use and Fatal error.
   
$a="\\namespacename\\classname"; //Valid use.
   
$a='\namespacename\classname'; //Valid use.
?>
up
15
guilhermeblanco at php dot net
14 years ago
Please be aware of FQCN (Full Qualified Class Name) point.
Many people will have troubles with this:

<?php

// File1.php
namespace foo;

class
Bar { ... }

function
factory($class) {
    return new
$class;
}

// File2.php
$bar = \foo\factory('Bar'); // Will try to instantiate \Bar, not \foo\Bar

?>

To fix that, and also incorporate a 2 step namespace resolution, you can check for \ as first char of $class, and if not present, build manually the FQCN:

<?php

// File1.php
namespace foo;

function
factory($class) {
    if (
$class[0] != '\\') {
        echo
'->';
        
$class = '\\' . __NAMESPACE__ . '\\' . $class;
    }

    return new
$class();
}

// File2.php
$bar = \foo\factory('Bar'); // Will correctly instantiate \foo\Bar

$bar2 = \foo\factory('\anotherfoo\Bar'); // Wil correctly instantiate \anotherfoo\Bar

?>
up
3
m dot mannes at gmail dot com
7 years ago
Case you are trying call a static method that's the way to go:

<?php
class myClass
{
    public static function
myMethod()
    {
      return
"You did it!\n";
    }
}

$foo = "myClass";
$bar = "myMethod";

echo
$foo::$bar(); // prints "You did it!";
?>
up
5
akhoondi+php at gmail dot com
10 years ago
It might make it more clear if said this way:

One must note that when using a dynamic class name, function name or constant name, the "current namespace", as in http://www.php.net/manual/en/language.namespaces.basics.php is global namespace.

One situation that dynamic class names are used is in 'factory' pattern. Thus, add the desired namespace of your target class before the variable name.

namespaced.php
<?php
// namespaced.php
namespace Mypackage;
class
Foo {
    public function
factory($name, $global = FALSE)
    {
        if (
$global)
           
$class = $name;
        else
           
$class = 'Mypackage\\' . $name;
        return new
$class;
    }
}

class
A {
    function
__construct()
    {
        echo
__METHOD__ . "<br />\n";
    }
}
class
B {
    function
__construct()
    {
        echo
__METHOD__ . "<br />\n";
    }
}
?>

global.php
<?php
// global.php
class A {
    function
__construct()
    {
        echo 
__METHOD__;
    }
}
?>

index.php
<?php
//  index.php
namespace Mypackage;
include(
'namespaced.php');
include(
'global.php');
 
 
$foo = new Foo();
 
 
$a = $foo->factory('A');        // Mypackage\A::__construct
 
$b = $foo->factory('B');        // Mypackage\B::__construct
 
 
$a2 = $foo->factory('A',TRUE);    // A::__construct
 
$b2 = $foo->factory('B',TRUE);    // Will produce : Fatal error: Class 'B' not found in ...namespaced.php on line ...
?>
up
1
scott at intothewild dot ca
14 years ago
as noted by guilhermeblanco at php dot net,

<?php

 
// fact.php

 
namespace foo;

  class
fact {

    public function
create($class) {
      return new
$class();
    }
  }

?>

<?php

 
// bar.php

 
namespace foo;

  class
bar {
  ...
  }

?>

<?php

 
// index.php

 
namespace foo;

  include(
'fact.php');
 
 
$foofact = new fact();
 
$bar = $foofact->create('bar'); // attempts to create \bar
                                  // even though foofact and
                                  // bar reside in \foo

?>
To Top