让我试着用例子来阐明什么是可能的、不可能的和计划的。
手册中的引用基本上意味着您可以拥有以下自定义实现类型:
use Doctrine\Common\Collections\Collection;
// MyCollection is the "implementation type"
class MyCollection implements Collection {
// ... interface implementation
// This is not on the Collection interface
public function myCustomMethod() { ... }
}
现在您可以按如下方式使用它:
class MyEntity {
private $items;
public function __construct() {
$this->items = new MyCollection;
}
// ... accessors/mutators ...
}
$e = new MyEntity;
$e->getItems()->add(new Item);
$e->getItems()->add(new Item);
$e->getItems()->myCustomMethod(); // calling method on implementation type
// $em instanceof EntityManager
$em->persist($e);
// from now on $e->getItems() may only be used through the interface type
换句话说,只要一个实体是新的(不是 MANAGED、DETACHED 或 REMOVED),你就可以自由地使用集合的具体实现类型,即使它并不漂亮。如果它不是新的,您必须只访问接口类型(最好是类型提示)。这意味着实现类型并不重要。当从数据库中检索持久化 MyEntity 实例时,它不会使用 MyCollection(构造函数不会被 Doctrine 调用,因为 Doctrine 只重构已经存在/持久化的对象,它永远不会创建“新”对象)。而且由于这样的实体是 MANAGED 的,因此无论如何都必须通过接口类型进行访问。
现在到什么计划。拥有自定义集合的更漂亮的方法是同时拥有自定义接口类型,例如 IMyCollection 和 MyCollection 作为实现类型。然后,要使其与 Doctrine 2 持久性服务完美配合,您需要实现自定义 PersistentCollection 实现,例如 MyPersistentCollection,如下所示:
class MyPersistentCollection implements IMyCollection {
// ...
}
然后你会告诉映射中的 Doctrine 为该集合使用 MyPersistentCollection 包装器(请记住,PersistentCollection包装了一个集合实现类型,实现了相同的接口,以便它可以在委托给底层集合实现之前/之后完成所有持久性工作类型)。
因此,自定义集合实现将包含 3 个部分:
- 接口类型
- 实现类型(实现接口类型)
- 持久包装类型(实现接口类型)
这不仅可以编写与 Doctrine 2 ORM 无缝协作的自定义集合,还可以仅编写自定义持久包装器类型,例如优化特定集合的延迟加载/初始化行为以满足特定应用程序的需求。
目前还不可能做到这一点,但它会做到的。这是编写和使用完全自定义集合的唯一真正优雅且功能齐全的方法,这些集合完美地集成到 Doctrine 2 提供的透明持久性方案中。