我不想让任何人说“你不应该重新发明轮子,使用开源 ORM”;我有即时需求,无法切换。
我正在做一个支持缓存的小 ORM。即使不支持缓存,我还是需要这个特性,来知道什么时候将对象写入存储或不写入。模式是 DataMapper。
这是我的方法:
- 我想避免运行时自省(introspection)(即猜测属性)。
- 我不想使用 CLI 代码生成器来生成 getter 和 setter(实际上我使用 NetBeans,使用 ALT+INSERT)。
- 我希望模型最接近 POPO(普通的旧 PHP 对象)。我的意思是:私有(private)属性,每个属性的“硬编码”getter 和 setter。
我有一个名为 AbstractModel
的抽象类,所有模型都继承了它。它有一个名为 isDirty()
的公共(public)方法和一个名为 is_dirty 的私有(private)(如果需要,也可以被保护)属性。它必须返回 true 或 false,具体取决于对象数据自加载以来是否发生了变化。
问题是:有没有办法在每个 setter $this->is_dirty = true编码的情况下提升内部标志
?我的意思是:除了业务逻辑需要更改代码外,大多数时候我都希望 setter 为 "is_dirty"
$this->attr = $value
。
其他限制是我不能依赖 __set
,因为在具体模型类上,属性已经作为私有(private)属性存在,所以永远不会在 setter 上调用 __set
。
有什么想法吗?接受来自其他 ORM 的代码示例。
我的一个想法是修改 NetBeans setters 模板,但我认为应该有一种方法可以在不依赖 IDE 的情况下执行此操作。
我的另一个想法是创 build 置器,然后用下划线或其他东西更改私有(private)属性的名称。这样 setter 将调用 __set
并在那里有一些代码来处理 "is_dirty"
标志,但这有点破坏了 POPO 概念,而且很丑陋。
最佳答案
Attention!
My opinion on the subject has somewhat changed in the past month. While the answer where is still valid, when dealing with large object graphs, I would recommend using Unit-of-Work pattern instead. You can find a brief explanation of it in this answer
我有点困惑what-you-call-Model 与 ORM 的关系。这有点令人困惑。特别是因为在 MVC 中,模型 是一个层(至少,thats how I understand it,而您的“模型” 似乎更像Domain Objects)。
我假设您拥有的代码如下所示:
$model = new SomeModel;
$mapper = $ormFactory->build('something');
$model->setId( 1337 );
$mapper->pull( $model );
$model->setPayload('cogito ergo sum');
$mapper->push( $model );
并且,我将假设 what-you-call-Model 有两个方法,供数据映射器使用的设计器:getParameters()
和 setParameters ()
。在映射器存储 what-you-call-Model 的状态之前调用 isDirty()
并调用 cleanState()
- 当映射器拉数据到 what-you-call-Model。
BTW, if you have a better suggestion for getting values from-and-to data mappers instead of
setParameters()
andgetParameters()
, please share, because I have been struggling to come up with something better. This seems to me like encapsulation leak.
这将使数据映射器方法看起来像:
public function pull( Parametrized $object )
{
if ( !$object->isDirty() )
{
// there were NO conditions set on clean object
// or the values have not changed since last pull
return false; // or maybe throw exception
}
$data = // do stuff which read information from storage
$object->setParameters( $data );
$object->cleanState();
return $true; // or leave out ,if alternative as exception
}
public static function push( Parametrized $object )
{
if ( !$object->isDirty() )
{
// there is nothing to save, go away
return false; // or maybe throw exception
}
$data = $object->getParameters();
// save values in storage
$object->cleanState();
return $true; // or leave out ,if alternative as exception
}
In the code snippet
Parametrized
is a name of interface, which object should be implementing. In this case the methodsgetParameters()
andsetParameters()
. And it has such a strange name, because in OOP, theimplements
word means has-abilities-of , while theextends
means is-a.
到这一部分你应该已经有了类似的东西......
下面是 isDirty()
和 cleanState()
方法应该做的事情:
public function cleanState()
{
$this->is_dirty = false;
$temp = get_object_vars($this);
unset( $temp['variableChecksum'] );
// checksum should not be part of itself
$this->variableChecksum = md5( serialize( $temp ) );
}
public function isDirty()
{
if ( $this->is_dirty === true )
{
return true;
}
$previous = $this->variableChecksum;
$temp = get_object_vars($this);
unset( $temp['variableChecksum'] );
// checksum should not be part of itself
$this->variableChecksum = md5( serialize( $temp ) );
return $previous !== $this->variableChecksum;
}
关于php - 在 ORM 模型中处理脏状态的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10940265/