Yii est un framework Web basé sur des composants et la classe CComponent est la classe de base pour tous les composants.
La classe CComponent fournit des sous-classes avec des interfaces de programmation basées sur des propriétés, des événements et des comportements.
1. Propriétés du composant (propriété)
La classe Ccomponent ne fournit pas de stockage variable des attributs, et une sous-classe doit fournir deux méthodes pour l'implémenter. La méthode getPropertyName() de la sous-classe fournit les données d'opération de valeur de $component->PropertyName, et la méthode setPropertyName($val) de la sous-classe fournit l'opération d'affectation de valeur de $component->PropertyName.
$width=$component->textWidth;???? // Récupère l'attribut textWidth
La méthode d'implémentation consiste à appeler la méthode fournie par la sous-classe $width=$component- >getTextWidth( )
$component->textWidth=$width;???? // Définir l'attribut textWidth
L'implémentation consiste à appeler la méthode fournie par la sous-classe $component ->setTextWidth($width )
public function getTextWidth() { return $this->_textWidth; } public function setTextWidth($value) { $this->_textWidth=$value; }
Les valeurs d'attribut du composant ne sont pas sensibles à la casse (les membres de la classe sont sensibles à la casse)
2. événements)
Un événement de composant est un attribut spécial qui enregistre (lie) un gestionnaire d'événement (qui peut être un nom de fonction, une méthode de classe ou une méthode d'objet) à un nom d'événement, et le gestionnaire est automatiquement appelé lorsque l'événement est évoqué.
Les événements de composant sont stockés dans le tableau $_e[] de CComponent. La valeur clé du tableau est le nom de l'événement. La valeur de la valeur clé est un objet Clist est un conteneur de file d'attente fourni par Yii. La méthode add() de Clist ajoute le handle de rappel de l'événement.
//Ajouter une fonction globale au traitement des événements
$component-> onBeginRequest="logRequest";
//Ajouter une méthode statique de classe au traitement des événements
$component-> onBeginRequest=array("CLog"," logRequest");
//Ajouter une méthode objet au traitement des événements
$component-> onBeginRequest=array($mylog," logRequest");
Raise event :
$component ->raiseEvent('onBeginRequest ', $event);
appellera automatiquement :
logRequest($event), Clog::logRequest($event) et $mylog. logRequest($event)
Le gestionnaire d'événements doit être défini comme suit :
function methodName($event)
{
……
}
$event paramètres Il s'agit d'une instance de CEvent ou de sa sous-classe, qui contient au moins les informations de "qui a raccroché cet événement".
Le nom de l'événement commence par "on", qui peut être utilisé pour distinguer les attributs et les événements dans __get() et __set().
3. Comportement du composant (comportement)
Le comportement d'un composant est une méthode d'extension des fonctionnalités d'un composant sans héritage (voir le modèle de stratégie dans les modèles de conception).
Les classes de comportement doivent implémenter l'interface IBehavior, et la plupart des comportements peuvent être étendus à partir de la classe de base CBehavior.
L'interface IBehavior propose 4 méthodes.
attach($component) s'associe au composant, detach($component) supprime l'association $component, getEnabled() et setEnabled() définissent la validité de l'objet de comportement.
L'objet de comportement est stocké dans le tableau $_m[] du composant. La valeur de la clé du tableau est la chaîne du nom du comportement et la valeur du tableau est l'objet de la classe de comportement.
Le composant étend un comportement via attachBehavior ($name,$behavior) :
$component-> attachBehavior ('render',$htmlRender)
Ajoute un nom de rendu à $component For comportement, $htmlRender doit être un objet qui implémente l'interface IBehavior, ou un tableau :
array( ‘class’=>’path.to.BehaviorClass’, ‘property1′=>’value1′, ‘property2′=>’value2′, * )
créera un objet de comportement et définira les valeurs d'attribut en fonction de la classe du tableau.
$htmlRender est stocké dans $_m['render'].
Lorsqu'une méthode non définie d'un composant est appelée en externe, la méthode magique __call()? traversera tous les objets de comportement et l'appellera si une méthode du même nom est trouvée.
Par exemple, $htmlRender a une méthode renderFromFile(), accessible directement en tant que méthode de composant :
$component-> renderFromFile ()
4.Analyse du code source des composants
//所有部件的基类 class CComponent { private $_e; private $_m; //获取部件属性、事件和行为的magic method public function __get($name) { $getter=’get’.$name; //是否存在属性的get方法 if(method_exists($this,$getter)) return $this->$getter(); //以on开头,获取事件处理句柄 else if(strncasecmp($name,’on’,2)===0 && method_exists($this,$name)) { // 事件名小写 $name=strtolower($name); // 如果_e[$name] 不存在,返回一个空的CList事件句柄队列对象 if(!isset($this->_e[$name])) $this->_e[$name]=new CList; // 返回_e[$name]里存放的句柄队列对象 return $this->_e[$name]; } // _m[$name] 里存放着行为对象则返回 else if(isset($this->_m[$name])) return $this->_m[$name]; else throw new CException(Yii::t(‘yii’,'Property “{class}.{property}” is not defined.’, array(‘{class}’=>get_class($this), ‘{property}’=>$name))); } /** * PHP magic method * 设置组件的属性和事件 */ public function __set($name,$value) { $setter=’set’.$name; //是否存在属性的set方法 if(method_exists($this,$setter)) $this->$setter($value); //name以on开头,这是事件处理句柄 else if(strncasecmp($name,’on’,2)===0 && method_exists($this,$name)) { // 事件名小写 $name=strtolower($name); // _e[$name] 不存在则创建一个CList对象 if(!isset($this->_e[$name])) $this->_e[$name]=new CList; // 添加事件处理句柄 $this->_e[$name]->add($value); } // 属性没有set方法,只有get方法,为只读属性,抛出异常 else if(method_exists($this,’get’.$name)) throw new CException(Yii::t(‘yii’,'Property “{class}.{property}” is read only.’, array(‘{class}’=>get_class($this), ‘{property}’=>$name))); else throw new CException(Yii::t(‘yii’,'Property “{class}.{property}” is not defined.’, array(‘{class}’=>get_class($this), ‘{property}’=>$name))); } /** * PHP magic method * 为isset()函数提供是否存在属性和事件处理句柄的判断 */ public function __isset($name) { $getter=’get’.$name; if(method_exists($this,$getter)) return $this->$getter()!==null; else if(strncasecmp($name,’on’,2)===0 && method_exists($this,$name)) { $name=strtolower($name); return isset($this->_e[$name]) && $this->_e[$name]->getCount(); } else return false; } /** * PHP magic method * 设置属性值为空或删除事件名字对应的处理句柄 */ public function __unset($name) { $setter=’set’.$name; if(method_exists($this,$setter)) $this->$setter(null); else if(strncasecmp($name,’on’,2)===0 && method_exists($this,$name)) unset($this->_e[strtolower($name)]); else if(method_exists($this,’get’.$name)) throw new CException(Yii::t(‘yii’,'Property “{class}.{property}” is read only.’, array(‘{class}’=>get_class($this), ‘{property}’=>$name))); } /** * PHP magic method *?CComponent未定义的类方法,寻找行为类里的同名方法,实现行为方法的调用 */ public function __call($name,$parameters) { // 行为类存放的$_m数组不空 if($this->_m!==null) { // 循环取出$_m数组里存放的行为类 foreach($this->_m as $object) { // 行为类对象有效,并且方法存在,调用之 if($object->enabled && method_exists($object,$name)) return call_user_func_array(array($object,$name),$parameters); } } throw new CException(Yii::t(‘yii’,'{class} does not have a method named “{name}”.’, array(‘{class}’=>get_class($this), ‘{name}’=>$name))); } /** * 根据行为名返回行为类对象 */ public function asa($behavior) { return isset($this->_m[$behavior]) ? $this->_m[$behavior] : null; } /** * Attaches a list of behaviors to the component. * Each behavior is indexed by its name and should be an instance of *?{@link?IBehavior}, a string specifying the behavior class, or an * array of the following structure: *
* array( *???? ‘class’=>’path.to.BehaviorClass’, *???? ‘property1′=>’value1′, *???? ‘property2′=>’value2′, * ) *
* @param array list of behaviors to be attached to the component * @since 1.0.2 */ public function attachBehaviors($behaviors) { // $behaviors为数组 $name=>$behavior foreach($behaviors as $name=>$behavior) $this->attachBehavior($name,$behavior); } /** * 添加一个行为到组件 */ public function attachBehavior($name,$behavior) { /* $behavior不是IBehavior接口的实例,则为 * array( *???? ‘class’=>’path.to.BehaviorClass’, *???? ‘property1′=>’value1′, *???? ‘property2′=>’value2′, * ) * 传递给Yii::createComponent创建行为了并初始化对象属性 */ if(!($behavior instanceof IBehavior)) $behavior=Yii::createComponent($behavior); $behavior->setEnabled(true); $behavior->attach($this); return $this->_m[$name]=$behavior; } /** * Raises an event. * This method represents the happening of an event. It invokes * all attached handlers for the event. * @param string the event name * @param CEvent the event parameter * @throws CException if the event is undefined or an event handler is invalid. */ public function raiseEvent($name,$event) { $name=strtolower($name); // _e[$name] 事件处理句柄队列存在 if(isset($this->_e[$name])) { // 循环取出事件处理句柄 foreach($this->_e[$name] as $handler) { // 事件处理句柄为全局函数 if(is_string($handler)) call_user_func($handler,$event); else if(is_callable($handler,true)) { // an array: 0 – object, 1 – method name list($object,$method)=$handler; if(is_string($object))?// 静态类方法 call_user_func($handler,$event); else if(method_exists($object,$method)) $object->$method($event); else throw new CException(Yii::t(‘yii’,'Event “{class}.{event}” is attached with an invalid handler “{handler}”.’,array(‘{class}’=>get_class($this), ‘{event}’=>$name, ‘{handler}’=>$handler[1]))); } else throw new CException(Yii::t(‘yii’,'Event “{class}.{event}” is attached with an invalid handler “{handler}”.’,array(‘{class}’=>get_class($this), ‘{event}’=>$name, ‘{handler}’=>gettype($handler)))); // $event 的handled 设置为true后停止队列里剩余句柄的调用 if(($event instanceof CEvent) && $event->handled) return; } } else if(YII_DEBUG && !$this->hasEvent($name)) throw new CException(Yii::t(‘yii’,'Event “{class}.{event}” is not defined.’, array(‘{class}’=>get_class($this), ‘{event}’=>$name))); } }
以上就是Yii框架分析(二)——CComponent类剖析的内容,更多相关内容请关注PHP中文网(www.php.cn)!