通过命名空间避免 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:
- integration tests.
We don't allow any commit to merge into our repository that would result in a broken GraphQL schema. [...]
- 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_Product 和 EDD_Product,从而避免冲突。
此外,命名空间还能让 GraphQL Schema 更加优雅:如果 WooCommerce 希望确保自己的插件永远不会产生冲突,就必须在类型名称本身上「加命名空间」:WCProduct、WCDownload 和 WCPayment(或者,为了完全确保始终有效,可能会将其命名为 WooCommerceProduct、WooCommerceDownload 和 WooCommercePayment)。有了命名空间,这些类型就可以使用更自然的名称 Product、Download 和 Payment。