首頁 > php教程 > PHP开发 > Yii框架分析(二)-CComponent類剖析

Yii框架分析(二)-CComponent類剖析

黄舟
發布: 2016-12-27 11:04:05
原創
1252 人瀏覽過

Yii是基於元件(component-based)的web框架,CComponent類別是所有元件的基底類別。

CComponent類別為子類別提供了基於屬性(property)、事件(event)、行為(behavior)程式介面。

1.組件的屬性(property)

Ccomponent類別並沒有提供屬性的變數存儲,需要由子類別來提供兩個方法來實現。子類別的getPropertyName()方法提供$component->PropertyName的取值操作數據,子類別的setPropertyName($val)方法提供$component->PropertyName賦值運算。

$width=$component->textWidth;???? // 取得textWidth 屬性

實作方式為呼叫子類別提供的方法$width=$component->getTextWidth()

$component> width;???? // 設定textWidth 屬性

實作方式為呼叫子類別提供的方法$component->setTextWidth($width)

public function getTextWidth()
{
    return $this->_textWidth;
}
 
public function setTextWidth($value)
{
    $this->_textWidth=$value;
}
登入後複製

元件的屬性值是大小寫不敏感的(類別的成員時大小寫敏感的)

2.組件的事件(event)

元件事件是一種特殊的屬性,它可以將事件處理句柄(可以是函數名、類別方法或物件方法)註冊(綁定)到一個事件名上,句柄在事件被喚起的時候被自動呼叫。
元件事件存放在CComponent 的$_e[]數組裡,數組的鍵值為事件的名字,鍵值的數值為一個Clist對象,Clist是Yii提供的一個隊列容器,Clist的方法add()添加事件的回調handle。

//新增一個全域函數到事件處理
$component-> onBeginRequest=”logRequest”;
//新增一個類別靜態方法到事件處理
$component-> onBeginRequest=array(“CLog”,” logRequest” ;
//新增一個物件方法到事件處理
$component-> onBeginRequest=array($mylog,” logRequest”);

喚起事件:
$component ->raiseEvent('onBeginRequest ', $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)

為$component添加了一個名字為render的行為,$htmlRender 需是一個實現IBehavior 介面的對象,或是一個陣列:

array( ‘class’=>’path.to.BehaviorClass’,
    ‘property1′=>’value1′,
    ‘property2′=>’value2′,
* )
登入後複製

會根據陣列的class來建立行為對象並設定屬性值。

$htmlRender被儲存到$_m[‘render’]。

外部呼叫一個元件未定義的方法時,魔術方法__call()?會遍歷所有行為對象,如果找到同名方法就呼叫之。

例如?$htmlRender?有個方法?renderFromFile(),則可以直接當做組件的方法來存取:


$component-> renderFromFile ()

4.CComponent源碼分析🎜
//所有部件的基类
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)!


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門推薦
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板