Yii如何将CActiveRecord的属性数组link赋给class成员?

How does Yii link the attributes array of CActiveRecord to the class members?

我以前从未见过这个,想了解一下。这是我的代码 运行:

$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']就跟着改; $tmp$tmp2 之后将设置为 'Display'。

class 成员如何链接到这样的数组?这不适用于 class 的所有 public 成员(我预料到了这一点)。我只想知道我自己怎么做,因为它看起来很有趣!

equipmentType 不是 public 属性。

当你find(或findAll)调用CActiveRecord, populateRecord()时,它有以下代码($attributes是来自数据库的列=>值对. 请特别注意 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'] 填充了数据库中的数据。

如果您随后尝试引用伪 属性 equipmentType,您实际上最终会调用 CActiveRecord 实例上的魔法 __get() 方法。

如您所见,第一个 if 语句将为真,导致存储的值被 returned。

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() 方法,该方法再次,将 return 属性存储在 _attributes 属性.

所以,长话短说,大量使用(或滥用)魔术 __get 和 __set 方法允许这种情况发生。注意,我相信(但我自己还没有完全追踪逻辑)为了使用数组语法访问 attributes,你必须像 CActiveRecord 一样,在你的 class 上实现 ArrayAccess

只需按照文档页面说明,查看 CActiveRecord 如何实现所需的方法,您应该能够重复结果。