Yii はコンポーネントベースの Web フレームワークであり、CComponent クラスはすべてのコンポーネントの基本クラスです。
CComponent クラスは、プロパティ、イベント、および動作に基づいたプログラミング インターフェイスを備えたサブクラスを提供します。
1. コンポーネントのプロパティ (プロパティ)
Ccomponent クラスはプロパティの変数ストレージを提供せず、2 つのメソッドを提供するにはサブクラスによって実装する必要があります。サブクラスの getPropertyName() メソッドは $component->PropertyName の値操作データを提供し、サブクラスの setPropertyName($val) メソッドは $component->PropertyName の値割り当て操作を提供します。
$width=$component->textWidth;???? // textWidth 属性を取得します
実装では、サブクラス $width=$component->getTextWidth() によって提供されるメソッドを呼び出します
$component -> textWidth=$width;???? // textWidth 属性を設定します
実装方法は、サブクラス $component->setTextWidth($width) によって提供されるメソッドを呼び出すことです
public function getTextWidth() { return $this->_textWidth; } public function setTextWidth($value) { $this->_textWidth=$value; }
コンポーネントは大文字と小文字を区別しません (クラス メンバーは大文字と小文字を区別します)
2. コンポーネント イベント (イベント)
コンポーネント イベントは、イベント ハンドラー (関数名、クラス メソッド、またはイベント ハンドラー) を登録 (バインド) できる特別な属性です。オブジェクト メソッド) ) をイベント名に設定すると、イベントが呼び出されたときにハンドラーが自動的に呼び出されます。
コンポーネントイベントは、CComponent の $_e[] 配列に格納されます。キー値の値は、Yii が提供する Clist オブジェクトです。 Clist の add() はコールバック ハンドルを追加します。
//イベント処理にグローバル関数を追加
$component-> onBeginRequest="logRequest";
//イベント処理にクラスの静的メソッドを追加
$component-> onBeginRequest=array("CLog"," logRequest ");
//イベント処理にオブジェクトメソッドを追加
$component-> onBeginRequest=array($mylog," logRequest");
Raise event:
$component ->raiseEvent('onBeginRequest ', $event );
自動的に呼び出します:
logRequest($event)、Clog::logRequest($event)、$mylog.logRequest($event)
イベント ハンドルは次のように定義する必要があります:
function methodName($event)
{
……
}
$event パラメータは CEvent またはそのサブクラスのインスタンスであり、少なくとも「誰がこのイベントを切断したか」の情報が含まれています。
イベントの名前は「on」で始まり、__get() と __set() で属性とイベントを区別するために使用できます。
3. コンポーネントの動作 (動作)
コンポーネントの動作は、継承せずにコンポーネントの機能を拡張する方法です (デザイン パターンの戦略パターンを参照)。
Behavior クラスは IBehavior インターフェイスを実装する必要があり、ほとんどの動作は CBehavior 基本クラスから拡張できます。
IBehavior インターフェイスには 4 つのメソッドが用意されています。
attach($component) は自身をコンポーネントに関連付け、detach($component) は $component の関連付けを削除し、getEnabled() と setEnabled() は動作オブジェクトの有効性を設定します。
動作オブジェクトはコンポーネントの $_m[] 配列に格納されます。配列のキー値は動作名の文字列、配列値は動作クラス オブジェクトです。
コンポーネントは、attachBehavior ($name,$behavior) を通じて動作を拡張します。
$component->attachBehavior ('render',$htmlRender)
render という名前の動作を $component に追加します。$htmlRender は An オブジェクトである必要があります。 IBehavior インターフェースまたは配列を実装するもの:
array( ‘class’=>’path.to.BehaviorClass’, ‘property1′=>’value1′, ‘property2′=>’value2′, * )
は動作オブジェクトを作成し、配列のクラスに基づいて属性値を設定します。
$htmlRender は $_m[‘render’] に保存されます。
コンポーネントの未定義のメソッドが外部から呼び出される場合、マジック メソッド __call()? はすべての動作オブジェクトを走査し、同じ名前のメソッドが見つかった場合はそれを呼び出します。
たとえば、$htmlRender? にはコンポーネント メソッドとして直接アクセスできる renderFromFile() があります:
4.Cコンポーネント ソース コード分析
//所有部件的基类 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)!