概念、想法、策略
概念、想法、策略通过命名空间避免 Schema 冲突

通过命名空间避免 Schema 冲突

WordPress 目录上发布插件的开发者无法预先知道谁会使用他们的插件,也不清楚站点将有怎样的配置或环境,包括可能安装了哪些其他插件。因此,插件必须做好应对冲突的准备,并提前采取预防措施。

WordPress 插件避免冲突的方法之一是使用 PHP 命名空间。命名空间在 PHP 社区中被广泛使用,遵循 PHP 标准建议 PSR-4 以启用 Composer 自动加载。PHP 包必须包含供应商名称,格式为 "vendor-name/package-name",相应的命名空间会出现在 PHP 代码中:

<?php
namespace VendorName\PackageName\ClassName;

命名空间在 GraphQL 的上下文中同样有意义,可用于避免 Schema 上可能发生的以下冲突:

  • 存在两个同名的类型
  • 同一类型上存在两个同名的字段
  • 存在两个同名的指令

命名空间已被提议纳入 GraphQL 规范

At the moment all GraphQL types share one global namespace. This is also true for all of the fields in mutation/subscription type. It can be a concern for bigger projects which may contain several loosely-coupled parts in a GraphQL schema.

然而,Lee Byron(在 Facebook 工作时 GraphQL 的创始人之一)认为向规范中添加命名空间并无必要。在这条评论中,他解释了 Facebook 如何在不产生冲突的情况下管理其 GraphQL Schema 中的数千个类型:

We avoid naming collisions in two ways:

  1. integration tests.

We don't allow any commit to merge into our repository that would result in a broken GraphQL schema. [...]

  1. Common naming patterns.

We have common patterns for naming things which naturally avoid collision problems. [...]

但是,这一策略在 Facebook 行之有效,并不意味着它在 WordPress 中同样适用:Facebook 控制着其 GraphQL Schema 的所有输入,因此可以遵循一套命名规范来确保不会产生冲突。而 WordPress 站点高度依赖第三方插件,无法控制这些插件的开发方式。

例如,如果一个站点同时使用了 WooCommerce 和 Easy Digital Downloads 插件,而两者都在 GraphQL Schema 中定义了名为 Product 的类型,就会产生冲突。站点所有者唯一的办法是联系其中一家公司,请求他们修改代码。这不是预防,而是事后补救,且并不可靠。

命名空间可以让 WordPress 站点所有者确信其代码始终能够正常运行。如果两个类型都叫 Product,站点管理员可以在 GraphQL Schema 中启用命名空间,这些类型将自动被重命名为 WooCommerce_ProductEDD_Product,从而避免冲突。

此外,命名空间还能让 GraphQL Schema 更加优雅:如果 WooCommerce 希望确保自己的插件永远不会产生冲突,就必须在类型名称本身上「加命名空间」:WCProductWCDownloadWCPayment(或者,为了完全确保始终有效,可能会将其命名为 WooCommerceProductWooCommerceDownloadWooCommercePayment)。有了命名空间,这些类型就可以使用更自然的名称 ProductDownloadPayment