PHP - ORM 延迟加载/身份映射实现问题

发布于 2024-09-24 20:11:48 字数 2115 浏览 1 评论 0原文

我有一个简单的 ORM 实现,由加载和持久化实体的数据映射器组成。每个映射器在内部管理从数据库读取的所有实体的身份映射,以便同一实体仅加载到内存中一次。

我目前正在使用代理类实现相关实体的延迟加载,该代理类仅在访问实体上的属性时才加载相关数据。我的问题是代理类不是实体本身,只有在间接加载实体(通过关系)时才使用。因此,任何将实际实体与加载相同实体的代理进行比较的 === 检查都将返回 false。我的目标是让实体和客户端代码都不知道代理对象。

代理类看起来像:

class EntityProxy
{
    protected $_entity;
    protected $_loader;

    public function __construct(EntityProxyLoader $loader)
    {
        $this->_loader = $loader;
    }

    protected function _load()
    {
        if (null === $this->_entity)
        {
            $this->_entity = $this->_loader->load();
            unset($this->_loader);
        }
    }

    public function __get($name)
    {
        $this->_load();
        return $this->_entity->$name;
    }

    public function __set($name, $value)
    {
        $this->_load();
        $this->_entity->$name = $value;
    }
}

映射器看起来像:

class PersonEntityMapper
{
    // Find by primary key
    public function find($id)
    {
        if ($this->inIdentityMap($id)
        {
            return $this->loadFromIdentityMap($id);
        }

        $data = ...;  // gets the data

        $person = new Person($data);

        // Proxy placeholder for a related entity. Assume the loader is
        // supplied the information it needs in order to load the related 
        // entity.
        $person->Address = new EntityProxy(new EntityProxyLoader(...));

        $this->addToIdentityMap($id, $person);

        return $person;
    }
}

class AddressEntityMapper
{
    // Find by primary key
    public function find($id)
    {
        ...

        $address = new AddressEntity($data);

        $address->Person = new EntityProxy(new EntityProxyLoader(...));

        $this->addToIdentityMap($id, $address);

        return $address;
    }
}

如果我加载具有相关“AddressEntity”的“PersonEntity”记录,然后直接通过“AddressEntityMapper”加载相同的“AddressEntity”记录并比较两个对象,它们不会相同(因为一个是委托的代理)。有什么方法可以覆盖 PHP 内置的对象比较吗?关于在不将代理感知代码引入实体和/或客户端代码的情况下处理此问题的更好方法有什么建议吗?

另外,我知道采用现有的和已建立的 ORM 对我有利,但有各种问题阻止我这样做。

I have a bare bones ORM implementation, consisting of data mappers which load and persist entities. Each mapper internally manages an identity map for all entities read from the database, so that the same entity is only loaded into memory once.

I am currently implementing lazy loading for related entities using a proxy class that loads the related data only when a property on the entity is accessed. My problem is that the proxy class is not the entity itself and is only used if the entity is loaded indirectly (via a relationship). So any === check comparing the actual entity with a proxy that loads the same entity will return false. My goal is to keep both the entities and client code unaware of the proxy objects.

The proxy class looks something like:

class EntityProxy
{
    protected $_entity;
    protected $_loader;

    public function __construct(EntityProxyLoader $loader)
    {
        $this->_loader = $loader;
    }

    protected function _load()
    {
        if (null === $this->_entity)
        {
            $this->_entity = $this->_loader->load();
            unset($this->_loader);
        }
    }

    public function __get($name)
    {
        $this->_load();
        return $this->_entity->$name;
    }

    public function __set($name, $value)
    {
        $this->_load();
        $this->_entity->$name = $value;
    }
}

And the mappers look something like:

class PersonEntityMapper
{
    // Find by primary key
    public function find($id)
    {
        if ($this->inIdentityMap($id)
        {
            return $this->loadFromIdentityMap($id);
        }

        $data = ...;  // gets the data

        $person = new Person($data);

        // Proxy placeholder for a related entity. Assume the loader is
        // supplied the information it needs in order to load the related 
        // entity.
        $person->Address = new EntityProxy(new EntityProxyLoader(...));

        $this->addToIdentityMap($id, $person);

        return $person;
    }
}

class AddressEntityMapper
{
    // Find by primary key
    public function find($id)
    {
        ...

        $address = new AddressEntity($data);

        $address->Person = new EntityProxy(new EntityProxyLoader(...));

        $this->addToIdentityMap($id, $address);

        return $address;
    }
}

If I load a "PersonEntity" record that has a related "AddressEntity", then load that same "AddressEntity" record directly via the "AddressEntityMapper" and compare the two objects, they will not be the same (as one is a proxy that delegates). Is there any way to override PHP's built in object comparison? Any suggestions on a better way to handle this without introducing proxy aware code into the entities and/or client code?

Also, I am aware that it would be in my benefit to adopt an existing and established ORM, but there are various issues that prevent me from doing so.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

薔薇婲 2024-10-01 20:11:48

通常的方法是创建一个 equals 方法,就像在 Java 中所做的那样。 PHP 不允许你重写 == 或 === 并且我从来没有找到重写比较器的方法,但我以前就犯过错误,如果我错了那就太酷了。

Usual method is to create an equals method like you would do in Java. PHP doesn't allow you to override == or === and I've never found a way to override comparators but I've been wrong before and it would be cool if I was wrong about this.

不确定你的问题,但我认为应该使用接口来完成比较,而不是 ===== 你应该使用 if($User instanceof UserInterface)

看:http://www.davegardner.me .uk/blog/tag/lazy-load/

Not sure about your issue, but I think that the comparison should be done using interfaces and instead of == or === you should use if($User instanceof UserInterface)

Look: http://www.davegardner.me.uk/blog/tag/lazy-load/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文