命名空间是什么?

279

什么是PHP命名空间?

一般说来,什么是命名空间?

一个例子来解释会更容易理解。


谢谢..... ☺️ - user16421015
12个回答

633

命名空间(Namespacing)对于函数和类的作用就像作用域对于变量的作用一样。它允许您在同一程序的不同部分中使用相同的函数或类名称,而不会导致名称冲突。

简单来说,将一个命名空间看作人的姓氏。如果有两个人叫“John”,您可以使用他们的姓氏来区分他们。

场景

假设您编写了一个使用名为output()的函数的应用程序。您的output()函数获取页面上的所有HTML代码并将其发送给用户。

随着应用程序越来越大,您想添加新功能。您添加了一个库,使您能够生成RSS源,该库还使用名为output()的函数来输出最终的源。

当您调用output()时,PHP如何知道是使用您的output()函数还是RSS库的output()函数?除非您使用命名空间,否则它不知道。

示例

那么我们如何解决两个output()函数的问题呢? 简单。 我们将每个output()函数放在自己的命名空间中。

看起来可能像这样:

namespace MyProject;

function output() {
    # Output HTML page
    echo 'HTML!';
}

namespace RSSLibrary;

function output(){
    # Output RSS feed
    echo 'RSS!';
}

稍后当我们想要使用不同的函数时,我们会使用:

\MyProject\output();
\RSSLibrary\output();

或者我们可以声明我们在其中一个命名空间中,然后我们就可以调用该命名空间的output()函数:

namespace MyProject;

output(); # Output HTML page
\RSSLibrary\output();

没有命名空间?

如果没有命名空间,每次添加一个库时我们就必须(可能)改变很多代码,或者编写繁琐的前缀来使函数名唯一。有了命名空间,我们可以避免在将第三方代码与自己的项目混合时出现名称冲突的麻烦。


由于某种原因,我认为如果在file1中使用命名空间,就不需要在file2中require或include该文件。单元测试表明这并不是事实。 - user11104582
1
@AaronBell 你可能想要了解一下自动加载(https://www.php.net/manual/en/language.oop5.autoload.php)。 - cbednarski

22
一个命名空间允许你将一堆代码放在一个名称下,并且不会与类、函数和常量产生任何命名冲突。
它允许你的代码“存在”于该命名空间中。
PHP使用有些争议的字符 \ 来显示命名空间级别。人们感到不满,因为它也用作转义字符。
要在PHP中使用命名空间,请在文件顶部使用类似以下的语句。
namespace my\namespace;

您可以在官方PHP文档的命名空间部分中找到更多相关信息。


12

由于通过了解“命名空间”而更容易学习关键字“use”,因此让我先通过查看基本的Laravel项目来解释命名空间。

有一个控制器类的名称为:Controller.php ,它位于从项目根目录开始的路径app/Http/Controllers中。还有另一个名为Controller.php的控制器类,但是该类位于从项目根目录开始的路径vendor/laravel/framework/src/Illuminate/Routing中。

如果您是php新手,则不需要查看源代码,因为这可能会使您困惑,相反让我向您解释我们关心并将帮助我们理解“命名空间”和“use”的部分。

事实上,第一个控制器类:app/Http/Controllers/Controller.php需要使用第二个控制器类vendor/laravel/framework/src/Illuminate/Routing/Controller.php。它实际上需要扩展此类以便可以访问其内容,以处理一些关键路由功能。

那么一个类如何扩展另一个同名类呢? class Controller extends Controller? 这将不起作用, 除非有一种方法可以区分这两个类,这就是namespace的作用以及use关键字帮助完成的任务, 允许在相同范围内使用具有相同名称的(类;方法;接口和常量)。

那么如何在代码中实现呢?非常简单!如果我们查看app/Http/Controllers/Controller.php源代码,我们可以看到类的顶部声明了命名空间:namespace App\Http\Controllers,因此这是您为类提供命名空间的方式,以便可以被其他类引用。 现在这看起来与从项目根目录到此类的路径相同,有点不同之处是使用“\”而不是“/(windows命令提示符相同), 但还有另一个区别,即命名空间中的大写“A”与路径中小写“a”的区别。还要注意命名空间区分大小写。

因此,命名空间是路径的一个单独概念,如果有帮助,它可以遵循路径结构,但不必是类,方法,接口或常量的确切路径。例如,请查看: vendor/laravel/framework/src/Illuminate/Routing/Controller.php源代码。

我们可以看到在类的顶部声明了命名空间为:Illuminate\Routing

现在让我们来看一下“use”关键字,使用“use”关键字可以让我们的类知道我们想要在其中使用的特定类或函数。

所以我们并没有导入或包含任何东西,只是通过引用它们的命名空间让我们的类知道我们将使用特定的类或方法。 让我们来看一下app/Http/Controllers/Controller.php源码, 你可以从这行代码中看到:“use Illuminate\Routing\Controller as BaseController”, “use”关键字后面跟着目标类的命名空间 (请注意,Illuminate\Routing\Controller.php和Illuminate\Routing\Controller '不带.php扩展名' 是可以互换的)

我们可以使用“as”关键字与“use”关键字一起给特定的类、方法、接口或常量设置别名,这样就允许 app/Http/Controllers/Controller.php在“class Controller extends BaseController”这行代码中扩展Illuminate\Routing\Controller.php作为BaseController。


8

在其他编程语言中,如Java中的包,有诸如命名空间之类的技术。它们用于在项目中拥有多个具有相同名称的类。

来自php文档(http://www.php.net/manual/en/language.namespaces.rationale.php):

什么是命名空间?在最广泛的定义中,命名空间是一种封装项目的方式。这可以在许多地方看作是一个抽象概念。例如,在任何操作系统中,目录用于分组相关文件,并作为其中文件的名称空间。作为一个具体的例子,在目录/home/greg和/home/other中都可以存在文件foo.txt, 但两个foo.txt的副本不能同时存在于同一目录中。此外,要在/home/greg目录之外访问foo.txt文件,我们必须使用目录分隔符将目录名添加到文件名前以获取/home/greg/foo.txt。这个原则在编程世界中也适用于命名空间。


2
与Java进行比较是一个不好的想法。Java拥有包和包可见性类。受保护成员的可见性也取决于访问它的包。 - Artefacto
2
它们不等同于包,但它们分享相同的概念。 - 2ndkauboy
由于问题也询问了命名空间的一般概念,因此答案是有意义的。 - apaderno
@kiam 他们有一个共同的想法——非冲突的类名。但他们并不认同可见性的想法。 - Artefacto
@Artefacto:Kau-Boy并没有说两种语言中的命名空间是相同的。 - apaderno

5

与目录和文件类似,PHP中的命名空间用于将类、函数、接口和常量分组。

示例:

Filesystem      |   PHP Namespace
----------------|------------------
/Dir/File.txt   |  \Namespace\Class

它提供了一种从全局空间包装项目的方法,并允许在程序中使用普通项目名称而不会引起名称冲突。

它支持PHP 5.3.0,PHP 7。

但是,在PHP命名空间和基于Unix的文件系统之间进行类比存在一些限制:

                          | Filesystem            |        PHP Namespace
--------------------------|-----------------------|-------------------------
Cas sensitive             |       No              |        Yes                
--------------------------|-----------------------|-------------------------
Name with plain number    |       Yes             |        No
--------------------------|-----------------------|-------------------------
Path level                |       Yes             |        Yes   
--------------------------|-----------------------|-------------------------
Plain metacharacters name |       Yes             |        No        

原则也适用于编程中的命名空间。

5

命名空间就像一个目录。你知道如何将文件放在与父目录(或任何其他目录)中的文件同名的目录中吗?好的,命名空间允许您在应用程序中为变量、函数和类做到这一点。

PHP语言中曾经有一段时间流行使用大量静态函数的类。唯一调用这些函数的方式是在调用前加上类名前缀。这是对命名空间的原始尝试,但没有太多的好处。


3

命名空间类似于将许多东西打包成一个单独的包。想象一下,命名空间就像一个抽屉,你可以把各种东西放进去:铅笔、尺子、一张纸等等。为了避免使用彼此的物品,你决定标记抽屉,以便清楚地知道属于谁的东西。


2

命名空间基本上是将代码放入一个容器中。这将防止两个函数(以及类和变量)共享相同的名称而导致问题。

当处理较大的应用程序时,这些非常有用,可以防止代码片段共享相同的名称而引起问题。

例如,假设我们想要两个名为"TheMessage"的函数。它们都将打印(echo)不同的消息。 通常,这会导致语法错误,因为您不能有两个共享相同名称的函数。

要解决此问题,您可以将这些函数放入单独的命名空间中。这将允许您在没有任何错误的情况下使用两个函数。


0

我们经常需要给资源命名,即一个标签,帮助我们理解和谈论它是什么。但是命名不仅仅是简单地分配一系列字符的任务。名称用于区分一件事物与另一件事物。

尽管标识符指代单个资源,但这并不意味着没有两个标识符是相同的。

我们可以通过GUID或添加有关命名空间的信息来防止或减少标识符冲突。命名空间是选择名称或标识符的域。当我们将命名空间添加到标识符中时,我们创建了限定名称

举个例子!

假设在邮政编码99501中只有一个JOHN_SMITH。在邮政编码86302中也只有一个JOHN_SMITH。那么,当我们提到JOHN_SMITH时,我们如何知道我们正在谈论哪个JOHN_SMITH

当我们在邮政编码99501的上下文中谈论并提到JOHN_SMITH时,我们正在谈论居住在邮政编码99501的JOHN_SMITH

<?php

namespace zc99501;

const JOHN_SMITH = "John Smith from 99501";

?>

当我们在谈论邮编86302的情况,并提到JOHN_SMITH时,我们指的是居住在邮编86302的JOHN_SMITH

<?php

namespace zc86302;

const JOHN_SMITH = "John Smith from 86302";

?>

现在假设来自邮编99501的一个人和来自邮编86302的另一个人想要谈论JOHN_SMITH。他们必须说JOHN_SMITH来自99501做了这件事,而JOHN_SMITH来自86302做了那件事。

<?php

namespace zc99501;

const JOHN_SMITH = "John Smith from 99501";

namespace zc86302;

const JOHN_SMITH = "John Smith from 86302";

namespace Test;

echo \zc99501\JOHN_SMITH . PHP_EOL;
echo \zc86302\JOHN_SMITH . PHP_EOL;

?>

这里,\zc99501\JOHN_SMITH\zc86302\JOHN_SMITH 是合格的名称。

另一个例子。

假设在某个上下文中,我们使用常量title时指的是书名,而name则表示作者姓名

<?php

namespace Book;

const title = "Don Quixote";
const name = "Miguel de Cervantes Saavedra";

?>

在另一个上下文中,我们用title指代角色的称号,用name指代角色的名字
<?php

namespace Character;

const title = "Sir";
const name = "Sancho Panza";

?>

当我们想要在两个上下文中使用titlename时,我们必须明确区分书名角色名称之间的差异。我们还必须明确区分作者姓名角色名称之间的差异。

<?php

namespace Book;

const title = "Don Quixote";
const name = "Miguel de Cervantes Saavedra";

namespace Character;

const title = "Sir";
const name = "Sancho Panza";

namespace Test;

echo \Book\title . PHP_EOL;
echo \Book\name . PHP_EOL;
echo \Character\title . PHP_EOL;
echo \Character\name . PHP_EOL;

?>

这里,\Book\title\Book\name\Character\title\Character\name是合格的名称。

注意:在PHP中,只有四种类型的代码受命名空间的影响:类、接口、函数和常量。

就是这样。


0

命名空间用于封装一组代码,以便它们可以在不同的地方使用而不会发生名称冲突。 把它看作是jQuery的无冲突方法,你就能更好地理解它。


1
“jQuery no conflict method”是什么意思?它与PHP有什么关系? - Nico Haase

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接