命名空间和动态语言特性

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

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";

/* 注意,如果使用双引号,则必须使用 "\\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
?>

请务必阅读有关在字符串中转义命名空间名的说明

添加注释

用户贡献的注释 8 个注释

Alexander Kirk
13 年前
当从另一个命名空间扩展类时,该类应该实例化当前命名空间中的类,您需要传递命名空间。

<?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" 但您想要 "bar"
?>

您需要这样做

当从另一个命名空间扩展类时,该类应该实例化当前命名空间中的类,您需要传递命名空间。

<?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"
?>

(预览中似乎从源代码中删除了命名空间反斜杠,也许在主视图中有效。如果不是:fooA 被写为 \foo\A,barB 被写为 bar\B)
Daan
4 年前
需要了解的是,在使用动态类名时,需要使用 *完全限定名*。以下示例说明了动态类名和普通类名之间的区别。

<?php
namespace namespacename\foo;

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

$a = '\namespacename\foo\classname'; // 有效,为完全限定名
$b = 'namespacename\foo\classname'; // 有效,被视为带有前缀 "\" 的字符串
$c = 'foo\classname'; // 无效,应为完全限定名

// 使用动态类名
new $a; // bar
new $b; // bar
new $c; // [500]: / - Uncaught Error: Class 'foo\classname' not found in

// 使用普通类名
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
museyib dot e at gmail dot com
5 年前
使用动态访问命名空间元素时要小心。如果使用双引号,反斜杠将被解析为转义字符。

<?php
$a
="\namespacename\classname"; // 无效使用,导致致命错误。
$a="\\namespacename\\classname"; // 有效使用。
$a='\namespacename\classname'; // 有效使用。
?>
guilhermeblanco at php dot net
15 年前
请注意 FQCN(完全限定类名)的要点。
很多人对此会感到困惑。

<?php

// File1.php
namespace foo;

class
Bar { ... }

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

// File2.php
$bar = \foo\factory('Bar'); // 将尝试实例化 \Bar,而不是 \foo\Bar

?>

为了解决这个问题,并结合两步命名空间解析,你可以检查 $class 的第一个字符是否为 \,如果不是,则手动构建 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'); // 将正确实例化 \foo\Bar

$bar2 = \foo\factory('\anotherfoo\Bar'); // 将正确实例化 \anotherfoo\Bar

?>
akhoondi+php at gmail dot com
11 年前
如果这样说可能更清楚。

需要注意的是,在使用动态类名、函数名或常量名时,"当前命名空间"(如 https://php.net/manual/en/language.namespaces.basics.php 中所述)是全局命名空间。

动态类名的一种使用场景是 "工厂" 模式。因此,在变量名前添加目标类的所需命名空间。

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); // 将导致:Fatal error: Class 'B' not found in ...namespaced.php on line ...
?>
m dot mannes at gmail dot com
7 年前
如果你想调用一个静态方法,那么这就是正确的方法。

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

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

echo
$foo::$bar(); // 打印 "You did it!"
?>
anisgazig at gmail dot com
2 年前
<?php

// 单引号或双引号,动态命名空间类中的单反斜杠或双反斜杠。

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;

}

/* 如果你的命名空间名称或类名称以小写 n 开头,那么你应该注意使用单引号或双引号与反斜杠的组合 */

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";
//致命错误:未捕获错误:类 ' ame_of_country\Japan' 未找到
//在此语句中,"\name_of_country\Japan" 表示 - 首字母 n 带有 "\ == 换行符("\n)。为了解决这个问题,我们可以使用双反斜杠或带单个反斜杠的单引号。
$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";
//致命错误:未捕获错误:类 '\Country_Name ame' 未找到

//在此语句中,"\Country_Name\name" 在类名称的首字母 n 带有 "\ == 换行符("\n)。为了解决这个问题,我们可以使用双反斜杠或带单个反斜杠的单引号
$a = "\\Country_Name\\name";
//Country_Name\name::__construct
$o = new $a;

}

//"\n == 换行符不区分大小写,所以 "\N 不会影响

?>
scott at intothewild dot ca
15 年前
如 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'); // 尝试创建 \bar
// 即使 foofact 和
// bar 都位于 \foo 中

?>
To Top