我以前从未见过这个,并且想要了解它。这是我运行的代码:
$q = new CDbCriteria(array(
'condition'=>'"pKey" = :pKey',
'params' => array(':pKey'=>$id)
));
$oldmodel = Inventory::model()->find($q); //Inventory extends CActiveRecord
$oldmodel->equipmentType = 'Display';
$tmp = $oldmodel->equipmentType;
$tmp2 = $oldmodel->attributes['equipmentType'];
结果是,一旦我改变$oldmodel->equipmentType
,$oldmodel->attributes['equipmentType']
将会效仿; <{1}}和$tmp
之后将设置为“显示”。
如何将类成员链接到这样的数组?这不适用于班级的所有公共成员(我期望这样)。我只是想知道自己能做到这一点,因为它看起来很有趣!
答案 0 :(得分:1)
equipmentType
不是公共属性。
当您find
(或findAll
)CActiveRecord
时,会调用populateRecord(),其中包含以下代码($attributes
是列=&gt;来自数据库的值对。特别注意foreach
循环。):
public function populateRecord($attributes,$callAfterFind=true)
{
if($attributes!==false)
{
$record=$this->instantiate($attributes);
$record->setScenario('update');
$record->init();
$md=$record->getMetaData();
foreach($attributes as $name=>$value)
{
if(property_exists($record,$name))
$record->$name=$value;
elseif(isset($md->columns[$name]))
$record->_attributes[$name]=$value;
}
$record->_pk=$record->getPrimaryKey();
$record->attachBehaviors($record->behaviors());
if($callAfterFind)
$record->afterFind();
return $record;
}
else
return null;
}
因此,在您的情况下,$Inventory->_attribute['equipmentType']
将填充数据库中的数据。
如果您尝试引用psuedo属性equipmentType
,实际上最终会在CActiveRecord实例上调用魔术__get()方法。
如您所见,第一个if
语句将为true,导致返回存储的值。
public function __get($name)
{
if(isset($this->_attributes[$name]))
return $this->_attributes[$name];
elseif(isset($this->getMetaData()->columns[$name]))
return null;
elseif(isset($this->_related[$name]))
return $this->_related[$name];
elseif(isset($this->getMetaData()->relations[$name]))
return $this->getRelated($name);
else
return parent::__get($name);
}
请注意,__set()将以互补的方式工作,因此当您自己设置属性时(除了从数据库加载时),它也会更新_attributes
属性。
最后,当您尝试以attributes
作为数组访问$oldmodel->attributes['equipmentType'];
属性时,您实际上正在调用getAttributes()方法,该方法将再次返回属性存储在_attributes
属性中。
因此,长篇大论简短,大量使用(或滥用)魔法__get和__set方法可以实现这一点。请注意,我相信(但我自己并没有充分追踪逻辑),为了使用数组语法访问attributes
,您必须像CActiveRecord一样在您的类上实现ArrayAccess。
只需按照文档页面说明操作,看看CActiveRecord如何实现所需的方法,您应该能够重复结果。