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

(PHP 5 >= 5.3.0)

На реализацию пространств имен в 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 foofactory('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 foofactory('Bar'); // Will correctly instantiate \foo\Bar

$bar2 foofactory('\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 fooA {}
class 
{
    public function 
tell() {
        echo 
"bar";
    }
}
?>

<?php
include "File1.php";
include 
"File2.php";
$b = new barB;
$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 fooA {
    protected 
$namespace __NAMESPACE__;
}
class 
{
    public function 
tell() {
        echo 
"bar";
    }
}
?>

<?php
include "File1.php";
include 
"File2.php";
$b = new barB;
$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

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