DevTips – PHP 中的命名空间

已发表: 2020-03-06

大约一年前,WordPress 决定将所需的最低 PHP 版本从 5.2(自 2010 年开始使用)更新为最新版本。 事实上,今天 WordPress 推荐的 PHP 最低版本是最新版本之一:PHP 7.3。

如果您是一个简单的 WordPress 用户,这可能不会对您产生太大影响(除了这些新版本提供更好的性能之外)。

但是,如果您是开发人员,这些新的 PHP 版本有一些很棒的功能可以在您的插件和主题中使用。 今天,具体来说,我想和你谈谈一个已经与我们在一起很长时间的东西:命名空间。

WordPress 和代码前缀

作为 WordPress 开发人员,您学习的首要规则之一是“在我们所做的一切中使用前缀”以避免“名称冲突”。 正如我们在 WordPress 最佳实践中所读到的:

当您的插件使用与另一个插件相同的变量、函数或类名称时,就会发生命名冲突。

[为避免名称冲突],所有变量、函数和类都应以唯一标识符作为前缀。 前缀可防止其他插件覆盖您的变量并意外调用您的函数和类。 它也会阻止你做同样的事情。

开发 WordPress 插件的最佳实践

因此,例如,与其创建类似get_site_id的函数,不如将其命名为nelio_content_get_site_id 。 这样,我们能够快速识别某个函数 ( get_site_id ) 所属的插件 ( nelio_content ) 或主题,并避免在多个插件尝试定义相同函数时出现致命错误。

使用前缀是创建“命名空间”的基本方法; 当我们没有更好的选择时,我们必须实施一种解决方法。 所有使用相同前缀的元素都是相同集合或命名空间的一部分。 但这会导致不必要的更复杂的代码:名称更长是因为前缀除了模拟命名空间之外没有其他用途。

PHP 命名空间

PHP 5.3 版引入了命名空间的概念。 他们在文档中给出的定义对我来说似乎很好,所以我在这里复制它:

在最广泛的定义中,命名空间是一种封装项目的方式。 这在很多地方都可以看作是一个抽象的概念。 例如,在任何操作系统中,目录用于对相关文件进行分组,并充当其中文件的命名空间。 作为一个具体的例子,文件foo.txt可以同时存在于目录/home/greg/home/other中,但是foo.txt的两个副本不能共存于同一目录中。

在 PHP 世界中,命名空间旨在解决库和应用程序的作者在创建可重用代码元素(如类或函数)时遇到的两个问题:

1. 您创建的代码与内部 PHP 代码或第三方代码之间的名称冲突。

2. 别名(或缩短) Extra_Long_Names的能力,提高源代码的可读性。

PHP 文档

如何创建命名空间

在 PHP 中创建命名空间非常容易。 在您创建的 PHP 文件的开头,添加一个带有您要使用的名称的namespace指令,并且您在该文件中定义的“所有内容”都将属于该命名空间:

 <?php namespace Nelio_Content;

是的,就是这么简单! 现在,我们在那里创建的“一切”都将位于Nelio_Content命名空间中。 例如,如果我定义一个像我在开头提到的那样的函数:

 <?php namespace Nelio_Content; function get_site_id() { // ... }

我们现在知道get_site_idNelio_Content命名空间内。 这样,我们在定义函数时就不再需要使用nelio_content_前缀了。 伟大的!

命名空间的例外

如果您仔细查看到目前为止我告诉您的内容,您会发现我一直在引号中写“所有内容”:“我们添加的所有内容都将属于指定的名称空间。” 我为什么这样做? 因为命名空间并不绝对适用于我们编写的所有代码……有一些例外。

PHP 命名空间仅涵盖以下 PHP 元素:

  • 课程
  • 接口
  • 性状
  • 职能
  • const声明但没有用define声明的常量

此外,WordPress 中还有一些额外的东西也需要它们自己的命名空间,不幸的是,PHP 命名空间不包括:您的脚本句柄、数据库选项或自定义内容类型及其元数据等。在所有这些情况下,您必须继续使用前缀。

如何将元素从一个命名空间导入到另一个命名空间

如果您需要使用您自己的命名空间中的元素,您不必做任何特别的事情:只需通过它的名称来调用它。 例如,在以下代码片段中:

 <?php namespace Nelio_Content; function get_site_id() { // ... } function get_auth_token() { $site_id = get_site_id(); // ... }

您可以看到我们定义了两个函数: get_site_idget_auth_token ,都在Nelio_Content命名空间中。 当get_auth_token需要使用get_site_id时,它就像往常一样简单地调用它。

另一方面,如果您需要在不同的命名空间中使用get_site_id ,则必须使用其完整标识符调用该函数:

 <?php namespace Something_Else; function do_some_action() { $site_id = Nelio_Content\get_site_id(); // ... }

或者您必须使用关键字use导入函数:

 <?php namespace Something_Else; use Nelio_Content\get_site_id; function do_some_action() { $site_id = get_site_id(); // ... }

我个人非常喜欢第二个选项:使用关键字use从其他命名空间导入函数,您可以快速查看文件的标题并确定其依赖项。

带有 PHP 命名空间的 WordPress 过滤器和操作

在 WordPress 过滤器和操作旁边使用命名空间时,您应该记住一个重要的细节。 当您指定过滤器和操作回调时,通常通过将回调名称作为字符串提供:

 <?php // ... add_action( 'init', 'do_some_action' );

问题是,如果这个函数在一个命名空间内,之前的钩子将无法按预期工作; 你必须告诉 WordPress 函数的全名。 换句话说,你必须包含它的命名空间(如果有的话)。

您是否在定义命名空间本身的文件中添加了钩子? 没关系,用全名:

 <?php namespace Nelio_Content; function do_some_action() { // ... } add_action( 'init', 'Nelio_Content\do_some_action' );

您是否在另一个命名空间中,但您use导入了该函数? 也没关系,用全名:

 <?php namespace Something_Else; use Nelio_Content\do_some_action; // ... add_action( 'init', 'Nelio_Content\do_some_action' );

在我们的命名空间中使用别名

命名空间的另一个非常有趣的功能是别名。 想象以下场景:

 <?php namespace Nelio_Content; function get_site_id() { // ... }

如果我想在另一个命名空间中使用这个函数,我们已经看到我可以use来实现。 但是,如果我想在其中使用它的模块已经有一个名为get_site_id的函数,我将如何使用这个函数?

好吧,对我来说幸运的是,我们可以将我们的导入别名为新名称:

 <?php namespace Something_Else; use Nelio_Content\get_site_id as get_nc_site_id(); function get_site_id() { // ... } function do_some_action() { $nc_site_idd = get_nc_site_id(); // ... }

立即开始使用命名空间!

命名空间是避免名称冲突和组织代码的绝佳工具。 事实上,虽然我没有对这篇文章发表评论,但有一些标准(例如 PSR-4)允许 PHP 根据您使用的命名空间的结构以及您如何将代码组织到目录和文件中来自动加载类。

如果您还没有在项目中使用命名空间,我们建议您从现在开始这样做。 在评论中告诉我们您的经历!

Chaitanya Tvs 在 Unsplash 上的精选图片。