你现在的位置:首页 > PHP网站建设知识库 > Yii > 正文

Yii的组件机制

Yii的组件机制

组件机制,是Yii整个体系的思想精髓,在使用Yii之前,在做yii开发时,最应该先了解其组件机制,如果不了解这个机制,那么阅读Yii源代码会非常吃力。组件机制给Yii框架赋予了无穷的灵活性和可扩展性,可以毫不夸张地说,Yii框架的基础结构就是组件。大到CApplication对象、控制器、路由管理器(urlManager),小到一些其它插件,均是以组件形式存在的。

什么是Yii组件?

Yii中几乎所有可实例化并继承自CComponent的类,均可称为组件。

组件的特点是什么?

继承自CComponent类(直接继承或间接继承),拥有事件及行为机制,可在配置文件中定义其各个属性。

组件中的“事件”:

一个示例演示 组件事件如何运行。

/* 
 *一个控制器(Controller)其实也是组件,因为其最后还是继承的CComponentl类。 
 *这个例子也只仅仅演示组件事件将如何运行。 
 */  
class ComponentTestController extends Controller  
{  
    /* 
     *这定义一个事件onSubmit 
     *定义的格式是固定的。函数名称必须和$this->raiseEvent()的第一个参数名称一致。 
     *$event 是一个CEvent或者其子类的实例。 具体看第74行调用代码。 
     */  
    public function onSubmit($event){  
  
        /*这个方法意思是在调用onSubmit这个时间的时候,去触发执行绑定到这个时间的函数*/  
        $this->raiseEvent("onSubmit", $event);  
    }  
  
    /** 
     *这里的test1~test4都是自定义方法,用于绑定到onSubmit时间中。 
     *如果  onSubmit触发并且下面的某些方法被绑定,则被绑定方法会执行。 
     */  
    public function test1(){  
        echo "这是在促发onSubmit时候执行的函数1<br />";  
    }  
  
    public function test2(){  
        echo "这是在促发onSubmit时候执行的函数2<br />";  
    }  
  
    public function test3(){  
        echo "这是在促发onSubmit时候执行的函数3<br />";  
  
    }  
    /*带参数*/  
    public function test4($data){  
        echo "这是在促发onSubmit时候执行的函数4<br />";  
        echo "<pre>";  
        print_r($data->params);  
        echo "</pre>";  
    }  
  
  
    public function actionIndex(){  
        /** 
         **** 
         *有两种方式对onSuubmit事件进行方法绑定。 
         *下面绑定了多个方法,绑定方法按照被绑定的顺序进行执行。 
         **** 
         *绑定方法1.$this->onSubmit=$callback; 
         *绑定方法2.$this->attachEventHandler("onSubmit", $callback); 
         *$callback代表一个事件处理程序。 
         *    一个事件处理程序必须是一个有效的PHP回调。 
         *    如,一个指字全局函数名的字符串或一个数组,该数组包含两个元素, 第一个元素是一个对象, 第二个元素是这个对象的方法。 
         * 
         */  
        /*1.绑定方式一:使用setter方法绑定事件。初学者可能会惊讶于onSubmit属性为什么没定义就可以这样访问.....*/  
        //这里是绑定当前的test3函数,array里面的第一个元素是一个$this对象。  
        //如果绑定的是其他对象的里面的方法,比如 自定义了一个对象form 里面有add方法。就应该这么写:  
        //$form=new Form();  
        //$this->onSubmit=array($form,"add");  
        $this->onSubmit=array($this,"test3");  
        $this->onSubmit=array($this,"test1");  
        $this->onSubmit=array($this,"test2");  
        /*2.绑定方式二*/  
        $this->attachEventHandler("onSubmit", array($this,"test4"));  
  
        /** 
         * 触发(调用)onSubmit事件,这个时候绑定在onSubmit上面的所有方法(test1,test2,test3...)将按顺序执行 
         * 
         * new CEvent($this,array("name"=>"参数一","sex"=>"参数二"))中的$this表明触发这个onSubmit事件的对象谁! 
         * array("name"=>"参数一","sex"=>"参数二") 数组为传入到绑定函数中的参数数据 
         */  
        $this->onSubmit(new CEvent($this,array("name"=>"参数一","sex"=>"参数二")));  
  
    }  
  
}  

运行结果如下:

这是在促发onSubmit时候执行的函数3  
这是在促发onSubmit时候执行的函数1  
这是在促发onSubmit时候执行的函数2  
这是在促发onSubmit时候执行的函数4  

Array  
(  
    [name] => 参数一  
    [sex] => 参数二  
)  


下面这个是看到别人的文章中对组件事件的使用示例。
例如我们希望当表单提交的时候,将此事件通知给日志组件让其记录之
定义一个form组件(是组件就必须直接或者间接的继承CComponent),并定义一个onSubmit事件(事件名称自己写啦...)

class form extends CComponent {  
public function onSubmit($event) {  
$this->raiseEvent('onSubmit',  $event);  
}  
}  

在一段代码中实例化这个组件,比如在一个action中。

class PostController extends Controller  
{  
  
    public function actionUser{  
        //实例化一个上面定义好的from组件。(但首先要把这个组件代码文件引入进来吧.....0.0)  
        $form = new form();  
  
        $logOjbect =new logOjbect();//实例化一个对象,我们要用到这个对象中的方法。  
  
        //方法绑定了。把$logOjbect对象中的saveLog方法绑定到$form对象(专业点叫‘组件’...)中的onSubmit事件中。  
        $form ->attachEventHandler( 'onSubmit',  array($logOjbect, "saveLog") );  
  
        //触发事件并执行其绑定的方法。这里把POST过来的数据传递到$logOjbect对象中的saveLog方法中,由saveLog对数据进行处理.  
        $form->onSubmit(new CEvent($form, array('data'=>$_POST) ) );  
  
    }  
}  
  
//logObject代码  
class logObject {  
    public function saveLog($event) {  
            //接收数据  
            $data=$event->params ;  
            //TODO 对数据的保存操作  
    }  
}  


组件中的“行为”:行为就是一个特殊的类。

一个行为的运行示例。

1.先定义一个行为类。

/* 
 * 定义一个行为。 
 */  
class MyBehavior extends CBehavior {  
  
    public $name="行为中的name属性<br />";  
  
    public function test1(){  
        echo "行为中的一个方法Test1<br />";  
  
    }  
    public function test2(){  
        echo "行为中的一个方法Test2<br />";  
    }  
  
    public function test3(){  
        echo "行为中的一个方法Test3<br />";  
    }  
  
    public function events() {  
        return array(  
                'onSubmit' => 'test3',  //指定调用此行为的组件的onSubmit事件发生后,自动调用行为的test2  
        );  
    }  
}  

2.在一个类中(一个控制器组件或者其他地方,这里用控制器组件做示例)中使用上面定义的行为。

Yii::import('application.behavior.MyBehavior');  
class BehaviorTestController extends Controller  
{  
    //定义一个事件  
    public function onSubmit($event){  
        $this->raiseEvent("onSubmit", $event);  
    }  
  
    public function test1(){  
        echo "优先执行<br />";  
    }  
  
    public function actionIndex(){  
        //给组件绑定一个行为 MyBehavior(当然,这个行为的类文件也必须先引入进来了...)  
        $this->attachBehavior('myapp','MyBehavior');  
        /** 
         *一旦把行为帮到到这个组件当中,这个时候就可以使用行为类当中的所有方法和属性了。 
         *和当前组件的对象(这里是$this)调用自身属性方法一样.. 
         *注意:如果当前组件中存在和行为名称一样的方法,将只会执行组件中的方法。 
         *    如下:$this->test1()只会执行这个控制器组件中的test1方法 
         */  
  
            echo $this->name;//调用行为MyBehavior中的name属性  
            echo $this->test1();//这里将执行当前控制器组件的test1,而不是行为中的test1  
            echo $this->test2();//调用行为中的test2方法  
  
            //触发当前组件的onSbumit事件的时候,将会执行行为中的test3方法。  
            //因为这是在行为类MyBehavior中的events进行了事件绑定  
            $this->onSubmit(new CEvent($this));  
    }  
}  


运行结果如下:

行为中的name属性  
优先执行  
行为中的一个方法Test2  
行为中的一个方法Test3  


一个具有实际应用价值的示例,用以表明什么时候会用到行为。
我们经常要对用户输入的内容进行过滤处理,比如防止其输入html标签,这种情况下,我们也可以考虑使用行为机制处理之
1.先定义一个html过滤行为类

/**  
*定义一个标签过滤行为  
*  
/  
class myHtmlFilter extends CBehavior {  
  
    public $strip_tags = false ;  
    //绑定事件。如果绑定了这个行为的组件触发了filter事件,将自动运行filterHtml方法  
    public function events() {  
        return array(  
            'filter' => 'filterHtml',  
        );  
    }  
      
      
    public function filterHtml($event) {  
      
        if($event->sender instanceof CFormModel) {//事件发起者判断,如果事件是由 CFormModel 对象发起....  
            $input = $event->sender->attributes ;  
            $event->sender->attributes = $this->filter($input);  
        }  
    }  
      
    public function filter(&$data) {  
        return is_array($data)?array_map(array($this, 'filter'),$data):strip_tags($data);  
    }  
}  

2.绑定行为,使用行为。

$form = new FormModel;  
If($_POST) {  
        $form->attributes = $_POST ;  
          
        //给form组件绑定myHtmlFilter行为  
        $form->attachBehavior('myFilter', array(  
                        'class' => 'myHtmlFilter',  
                        'strip_tags' => true ,//给行为中的$strip_tags属性赋默认值  
        ));  
      
    //触发$from中的filter事件。这个时候行为中的filterHtml方法将自动调用  
    $form->filter(new CEvent($form) ) ;  
}  

总结:简单点,事件就是在事件这个方法被触发的时候可以自动的去执行被绑定好的一个或者一组方法(全局方法或者指定对象中的方法)。行为就是一个用以完成某种特殊功能的类。在组件(类)中用attachBehavior方法对行为进行绑定,绑定之后就可以再组件中使用行为中的所有方法和属性。