Namespaces e recursos de linguagem dinâmica

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

A implementação de namespaces do PHP é influenciada por sua natureza dinâmica como linguagem de programação. Assim, para converter código como o exemplo a seguir em código com namespace:

Exemplo #1 Acessando elementos dinamicamente

exemplo1.php:

<?php
class nomedaclasse
{
function
__construct()
{
echo
__METHOD__,"\n";
}
}
function
nomedafuncao()
{
echo
__FUNCTION__,"\n";
}
const
nomedaconstante = "global";

$a = 'nomedaclasse';
$obj = new $a; // imprime nomedaclasse::__construct
$b = 'nomedafuncao';
$b(); // imprime nomedafuncao
echo constant('nomedaconstante'), "\n"; // imprime global
?>
Deve-se usar o nome totalmente qualificado (nome da classe prefixado com o namespace). Observe que, como não há diferença entre um nome qualificado e um nome totalmente qualificado em um nome de classe, nome de função ou nome de constante dinâmico, a barra invertida inicial não é necessária.

Exemplo #2 Acessando dinamicamente elementos com namespace

<?php
namespace nomedonamespace;
class
nomedaclasse
{
function
__construct()
{
echo
__METHOD__,"\n";
}
}
function
nomedafuncao()
{
echo
__FUNCTION__,"\n";
}
const
nomedaconstante = "comnamespace";

/* note que, ao usar aspas duplas, "\\nomedonamespace\\nomedaclasse" deve ser usado */
$a = '\nomedonamespace\nomedaclasse';
$obj = new $a; // imprime nomedonamespace\nomedaclasse::__construct
$a = 'nomedonamespace\nomedaclasse';
$obj = new $a; // também imprime nomedonamespace\nomedaclasse::__construct
$b = 'nomedonamespace\nomedafuncao';
$b(); // imprime nomedonamespace\nomedafuncao
$b = '\nomedonamespace\nomedafuncao';
$b(); // também imprime nomedonamespace\nomedafuncao
echo constant('\nomedonamespace\nomedaconstante'), "\n"; // imprime comnamespace
echo constant('nomedonamespace\nomedaconstante'), "\n"; // também imprime comnamespace
?>

Certifique-se de ler a nota sobre escapamento de namespaces em strings.

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