Пространства имен и динамические особенности языка

(PHP 5 >= 5.3.0, PHP 7)

На реализацию пространств имен в PHP повлияли и динамические особенности языка. Преобразуем нижеследующий код для использования пространств имен:

Пример #1 Динамически доступные элементы

example1.php:

<?php
class classname
{
    function 
__construct()
    {
        echo 
__METHOD__,"\n";
    }
}
function 
funcname()
{
    echo 
__FUNCTION__,"\n";
}
const 
constname "global";

$a 'classname';
$obj = new $a// выводит classname::__construct
$b 'funcname';
$b(); // выводит funcname
echo constant('constname'), "\n"// выводит global
?>
Необходимо использовать абсолютное имя (имя класса с префиксом пространства имен). Обратите внимание, что нет никакой разницы между полным именем и абсолютным внутри динамического имени класса, функции или константы. Начальный обратный слеш не является необходимым.

Пример #2 Динамически доступные элементы пространства имен

<?php
namespace namespacename;
class 
classname
{
    function 
__construct()
    {
        echo 
__METHOD__,"\n";
    }
}
function 
funcname()
{
    echo 
__FUNCTION__,"\n";
}
const 
constname "namespaced";

include 
'example1.php';

$a 'classname';
$obj = new $a// выводит classname::__construct
$b 'funcname';
$b(); // выводит funcname
echo constant('constname'), "\n"// выводит global

/* обратите внимание, что при использовании двойных кавычек символ обратного слеша должен быть заэкранирован. Например, "\\namespacename\\classname" */
$a '\namespacename\classname';
$obj = new $a// выводит namespacename\classname::__construct
$a 'namespacename\classname';
$obj = new $a// также выводит namespacename\classname::__construct
$b 'namespacename\funcname';
$b(); // выводит namespacename\funcname
$b '\namespacename\funcname';
$b(); // также выводит namespacename\funcname
echo constant('\namespacename\constname'), "\n"// выводит namespaced
echo constant('namespacename\constname'), "\n"// также выводит namespaced
?>

Обязательно прочитайте примечание об экранировании имен пространства имен в строках.

Коментарии

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

?>
2009-06-16 15:04:00
http://php5.kiev.ua/manual/ru/language.namespaces.dynamic.html
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

?>
2009-08-07 18:33:34
http://php5.kiev.ua/manual/ru/language.namespaces.dynamic.html
Автор:
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 
{
    public function 
factory() {
        return new 
C;
    }
}
class 
{
    public function 
tell() {
        echo 
"foo";
    }
}
?>

<?php // File2.php
namespace bar;
class 
extends \foo\A {}
class 
{
    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 
{
    protected 
$namespace __NAMESPACE__;
    public function 
factory() {
       
$c $this->namespace '\C';
        return new 
$c;
    }
}
class 
{
    public function 
tell() {
        echo 
"foo";
    }
}
?>

<?php // File2.php
namespace bar;
class 
extends \foo\A {
    protected 
$namespace __NAMESPACE__;
}
class 
{
    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)
2011-07-06 03:57:08
http://php5.kiev.ua/manual/ru/language.namespaces.dynamic.html
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 language.namespaces.basics 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 
{
    function 
__construct()
    {
        echo 
__METHOD__ "<br />\n";
    }
}
class 
{
    function 
__construct()
    {
        echo 
__METHOD__ "<br />\n";
    }
}
?>

global.php
<?php 
// global.php
class {
    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 ...
?>
2013-08-09 19:17:21
http://php5.kiev.ua/manual/ru/language.namespaces.dynamic.html
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!";
?>
2017-02-25 20:36:54
http://php5.kiev.ua/manual/ru/language.namespaces.dynamic.html
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.
?>
2019-03-09 18:48:17
http://php5.kiev.ua/manual/ru/language.namespaces.dynamic.html
Автор:
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
2019-09-19 11:56:25
http://php5.kiev.ua/manual/ru/language.namespaces.dynamic.html
<?php

//single or double quotes with single or double backslash in dynamic namespace class.

namespace Country_Name{
class 
Mexico{
function 
__construct(){
echo 
__METHOD__,"<br>";
}
}

$a 'Country_Name\Mexico';//Country_Name\Mexico::__construct
$a "Country_Name\Mexico";
//Country_Name\Mexico::__construct
$a '\Country_Name\Mexico';
//Country_Name\Mexico::__construct
$a "\Country_Name\Mexico";
//Country_Name\Mexico::__construct
$a "\\Country_Name\\Mexico";
//Country_Name\Mexico::__construct
$o = new $a;

}

/* if your namespace name or class name start with lowercase n then you should be alart about the use of single or double quotes with backslash  */

namespace name_of_country{
class 
Japan{
function 
__construct()
{
    echo 
__METHOD__,"<br>";
}

}

$a 'name_of_country\Japan';
//name_of_country\Japan::__construct
$a "name_of_country\Japan";
//name_of_country\Japan::__construct
$a '\name_of_country\Japan';
//name_of_country\Japan::__construct
//$a = "\name_of_country\Japan";
//Fatal error: Uncaught Error: Class ' ame_of_country\Japan' not found 
//In this statement "\name_of_country\Japan" means -first letter n with "\ == new line("\n). for fix it we can use double back slash or single quotes with single backslash. 
$a "\\name_of_country\\Japan";
//name_of_country\Japan::__construct
$o = new $a;
}

namespace 
Country_Name{
class 
name{
function 
__construct(){
echo 
__METHOD__,"<br>";
}
}

$a 'Country_Name\name';
//Country_Name\Norway::__construct
$a "Country_Name\name";
//Country_Name\Norway::__construct
$a '\Country_Name\name';
//Country_Name\Norway::__construct
//$a = "\Country_Name\name";
//Fatal error: Uncaught Error: Class '\Country_Name ame' not found 

//In this statement "\Country_Name\name" at class name's first letter n with "\ == new line("\n). for fix it we can use double back slash or single quotes with single backslash
$a "\\Country_Name\\name";
//Country_Name\name::__construct
$o = new $a;

}

//"\n == new line are case insensitive so "\N could not affected

 
?>
2021-11-19 07:12:04
http://php5.kiev.ua/manual/ru/language.namespaces.dynamic.html

    Поддержать сайт на родительском проекте КГБ