Interesting. It seems it’s either a small bug or the documentation’s wrong. The thing is, it’s possible to add non-table-field-related “fake” attributes to CActiveRecords, and while getAttribute and setAttribute are properly checking that first, hasAttribute does not, even though its documentation states “Checks whether this AR has the named attribute”.
So either the documentation should read “Checks whether this AR’s table has the named attribute as a field”, or the function should be changed to
public function hasAttribute($name)
{
return property_exists($name) || isset($this->getMetaData()->columns[$name]);
}