2015-04-10 2 views
1

Я никогда раньше этого не видел и хотел бы это понять. Вот код, я побежал:Как Yii связывает массив атрибутов CActiveRecord с членами класса?

$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 будут установлены на «Отображать».

Как можно связать член класса с таким массивом? Это не работает для всех публичных членов класса (я ожидал этого). Я просто хочу знать, как я могу это сделать сам, потому что это кажется действительно интересным!

ответ

1

equipmentType не является общедоступным.

Когда вы 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'] заполняется данными из базы данных.

Если вы попытаетесь ссылаться на свойство psuedo equipmentType, вы на самом деле закончите вызов метода magic __get() экземпляра CActiveRecord.

Как вы можете видеть, первый оператор if будет правдой, в результате чего возвращается сохраненное значение.

Обратите внимание, что __set() будет работать в дополнительном пути, так что, когда вы устанавливаете сам атрибут (кроме как раз, когда он загружает из базы данных), то он обновляет _attributes свойства, а также.

Наконец, при попытке получить доступ к attributes свойства как массив, как вы делаете с $oldmodel->attributes['equipmentType'];, вы на самом деле вызовом getAttributes() метода, который снова будет возвращать атрибут, хранящийся в _attributes собственности.

Итак, длинный рассказ о коротком, тяжелом использовании (или злоупотреблении) магических методов __get и __set позволяет это произойти. Заметьте, я верю (но не полностью проследил логику), что для доступа к синтаксису массива attributes вы должны, как и CActiveRecord, реализовать ArrayAccess в своем классе.

Просто следуйте инструкциям на странице документации и посмотрите, как CActiveRecord реализует необходимые методы, и вы должны иметь возможность повторить результат.

+0

Очень хорошо объяснено! Спасибо за время. Я не знал о __get() или __set(). Здорово узнать что-то новое! – Klik

+0

Слово совета: все эти магические свойства полезны, но в то же время они нарушают принцип наименьшего удивления. Если вы их используете, используйте их с осторожностью и с конкретной целью, потому что они значительно увеличат кривую обучения любого, кто смотрит на ваш код, включая себя в 3, 6 или в течение нескольких месяцев. –

Смежные вопросы