Yii如何将CActiveRecord的属性数组链接到类成员?

时间:2015-04-10 16:44:34

标签: php yii

我以前从未见过这个,并且想要了解它。这是我运行的代码:

$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之后将设置为“显示”。

如何将类成员链接到这样的数组?这不适用于班级的所有公共成员(我期望这样)。我只是想知道自己能做到这一点,因为它看起来很有趣!

1 个答案:

答案 0 :(得分:1)

equipmentType不是公共属性。

当您find(或findAllCActiveRecord时,会调用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如何实现所需的方法,您应该能够重复结果。