我不想让任何人说:“你不应该推倒重来,使用一个开源ORM”; 我有一个直接的要求,不能切换。
我做一个小的ORM,支持缓存。 即使是不支持缓存,我想反正需要这个功能,要知道什么时候一个对象写入到存储与否。 该模式是DataMapper的。
这里是我的方法:
- 我想避免运行时内省(即猜测属性)。
- 我不希望使用CLI代码生成器生成getter和setter(真我使用NetBeans之一,使用ALT + INSERT)。
- 我希望模型是最接近POPO(普通旧PHP对象)。 我的意思是:为每个属性私有属性,“硬编码” getter和setter。
我有一个叫做抽象类AbstractModel
所有车型继承。 它有一个叫做公共方法isDirty()
与私人(可保护过,如果需要的话)的属性称为is_dirty。 如果对对象数据的变化与否,因为它加载它必须返回true或false根据。
问题是:有没有办法来提高内部标志"is_dirty"
无需在每个二传手编码$this->is_dirty = true
? 我的意思是:我希望有制定机构$this->attr = $value
大部分时间,除了需要对业务逻辑代码的变化。
其他限制是,我不能依靠__set
,因为在具体的模型类的属性已经存在了私人的,所以__set
没有被调用的制定者。
有任何想法吗? 从别人的ORM代码示例被接受。
我的一个想法是修改NetBeans的制定者模板,但我想应该有这样做而不依赖于IDE的方式。
另一种认为我是创造的制定者,然后用下划线或东西改变私有属性的名称。 这样的setter会调用__set
和有一些代码有对付"is_dirty"
的标志,但是这打破了POPO概念一点点,它的丑陋。
Attantion!
我关于这个问题的看法在过去的一个月中已经有所改变。 虽然这里仍然是有效的答案,与大对象图打交道时,我会建议使用单位-的-工作模式来代替。 你可以找到它的简要说明这个ansewer
我有点困惑如何什么,你呼叫模型与ORM。 它有点混乱。 特别是由于在MVC 模型是一个层(至少, 这就是我如何理解它 ,而你的“模型”在我看来,更像是域对象 )。
我会假设你拥有的是看起来像这样的代码:
$model = new SomeModel;
$mapper = $ormFactory->build('something');
$model->setId( 1337 );
$mapper->pull( $model );
$model->setPayload('cogito ergo sum');
$mapper->push( $model );
:而且,我会假设什么,你呼叫模型有两种方法,使用设计人员可通过数据映射器getParameters()
和setParameters()
而您致电isDirty()
映射器前门店什么,你呼叫模式的状态,并调用cleanState()
-当映射器拉入的数据是什么,您呼叫的模型 。
顺便说一句,如果你有获得价值更好的建议,从-和数据映射器,而不是setParameters()
和getParameters()
请分享,因为我一直在努力拿出更好的东西。 这似乎对我来说,封装泄漏。
这将使数据映射方法是这样的:
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
}
在代码段Parametrized
是界面的名称,对象应该被执行。 在这种情况下,方法getParameters()
和setParameters()
而且它有这样一个奇怪的名字,因为在OOP的implements
词的意思是有-能力-,而extends
的手段是-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;
}
我会做一个代理,例如设置:
class BaseModel {
protected function _set($attr, $value) {
$current = $this->_get($attr);
if($value !== $current) {
$this->is_dirty = true;
}
$this->$attr = $value;
}
}
然后,每个子类将通过调用implemnt其二传手_set()
和从不直接设置属性。 此外,你可以随时注入更多的类特定代码到每个子类的_set
并调用parent::set($attr, $processedValue)
如果需要的话。 然后,如果你想用魔术方法来创建这些代理到代理财产法_set
。 我想这心不是很POPO虽然。
虽然这个职位是旧的,但关于使用事件时isDirty()恰好通知监听器怎么样? 我会接近与事件的解决方案。