一本书最好的并不是它包含的思惟,而是它提出的思惟正如音乐的美好并不寄寓于它的调子,而在于我们心中的回响。CComponet类是Yii中影响最广的类。不仅Application持续自它,Event,Behavior,Action,Controller,Widget总之很多都是持续自它。在这里我们不一一列举,到底有哪些类是持续字CComponent类的。我们在这里主如果从实际意义上来解析CComponet的感化,角色。当读完本篇后,你应当对持续自Yii的CComponent的类有什么样的属性,什么样的特点和感化,了然于胸。
为了在生活生计中尽力阐扬本身的感化,酷爱人生吧。CComponent类是一个很重大的类,我们就遵守由粗到细的过程来讲解。让我们先直观感触感染下CComponet类是长什么样子的。
下图为CComponet的类视图
在申明这个类前,我们先简单介绍下php中几个首要的函数,在yii中,他们被频繁的应用。
__set() is run when writing data to inaccessible properties.
__get() is utilized for reading data inaccessible properties.
__isset() is triggered by calling isset() or empty() on inaccessible properties.
__unset() is invoked when unset() is used on inaccessible properties.
__call() is triggered when invoking inaccessible methods in an object context.
__callStatic() is triggered when invoking inaccessible methods in a static context.
上方是总php.net复制过来的,这里的英文都很简单,这里最关键的是要重视inaccessible这个字眼。
不过,为了下面能讲解的更顺畅,我捎带申明下吧。
__set默示,当以¥obj->variable=value这种情势保存值时,若是当这个variable不是class的属性时,也就是压根没有定义时,就会运行__set办法。那么有什么用呢?如许我们可以哄骗这个特点,捏造出很多属性来,比如这里,variable固然不存在,然则当他履行这个__set函数的时辰,我可以让其运行另一个函数,来获取对应的数值。是以,也可以借由这个来隐含应用setter。如许无论在应用便捷性上,还是安然性上都邑更好。
__get默示,当以¥obj->variable这种情势获取值时辰,若是当这个variable不是class的属性时,也就是压根没有定义时,就会运行__get办法。这个特点常备用来封装getter,具体的类似__set中的讲解。
__isset默示,当以isset(¥obj->variable)这种体式格式验证时辰,若是当这个variable不是class的属性时,也就是压根没有定义时,就会运行__isset办法,重视此时不会再运行__get办法了。因为运行__get办法就底子不是变量行动了。有悖于isset的初志。
__unset正好是__isset的逆向,这里就偷个懒不说了然,然则重视也不会运行__get。
__call默示,当以¥obj->method()这种情势进行函数调用时,若是这个method不存在,那么就会调用__call办法。
__callStatic,当以¥obj::method()这种情势进行函数调用时,若是这个method不存在,那么就会调用__callStatic办法。
Ok讲解完了,让我们言归正传。想要整体把握,须要深切懂得CComponet中的__call,__get,__isset,__set,__unset办法。
接下来,让我们逐个分化。
__set
1 public function __set(¥name,¥value)
2 {
3 ¥setter=""set"".¥name;
4 if(method_exists(¥this,¥setter))
5 return ¥this->¥setter(¥value);
6 else if(strncasecmp(¥name,""on"",2)===0 && method_exists(¥this,¥name))
7 {
8 // duplicating getEventHandlers() here for performance
9 ¥name=strtolower(¥name);
10 if(!isset(¥this->_e[¥name]))
11 ¥this->_e[¥name]=new CList;
12 return ¥this->_e[¥name]->add(¥value);
13 }
14 else if(is_array(¥this->_m))
15 {
16 foreach(¥this->_m as ¥object)
17 {
18 if(¥object->getEnabled() && (property_exists(¥object,¥name) || ¥object->canSetProperty(¥name)))
19 return ¥object->¥name=¥value;
20 }
21 }
22 if(method_exists(¥this,""get"".¥name))
23 throw new CException(Yii::t(""yii"",""Property "{class}.{property}" is read only."",
24 array(""{class}""=>get_class(¥this), ""{property}""=>¥name)));
25 else
26 throw new CException(Yii::t(""yii"",""Property "{class}.{property}" is not defined."",
27 array(""{class}""=>get_class(¥this), ""{property}""=>¥name)));
28 }
起首这个函数分4大块,分别为4-5行,6-13行,14-21行,22-27行,每一块都有特别的感化。
起首看4-5行,这里是看是否存在响应的setter(就是以set开首的,比如setComponents之类的),有的话则履行这个setter。
然后是6-13行,这个是专门为Yii的Event机制供给的,若是以on开首并且定义了同名的办法时,会履行此段。这里的函数体,实现了,即便你没有在类中定义形如onClick如许的属性,还是可以写入的。首要感化是当钱定义了Event后,将对应的EventHandler导入¥_e变量。这里涉及到你须要对Event有必然的懂得,若是不太懂得的,推荐浏览Yii中的Event和Behaviour懂得。
Ok,重视了,要记住¥_e是用来存放event Handler的并且是个CList(其实可以认为是一个Array)。
再看14-21行,当¥_m是个数组时,会遍历¥_m中的条目,这里插播一下,¥_m是什么?他其实就是一个装着Behavior的数组。那么为什么要断定起是不是数组,因为只有当是数组的时辰,才申明里面存在Behavior。插播停止,这就回来。我们接着看代码,遍历操纵将存在¥_m中的Behavior取了出来,当behavior必须启用,同时还要满足这个behavior类中存在须要写入的属性(这个属性可是实际存在的),若是不满足这个则须要满足这个behaivor中存在这个属性名对应的setter。当满足这些前提后,就申明可以经由过程¥object->¥name体式格式接见到,所以运行。
最后看22-27行,这项目组只是报错用的。当存在getter时辰,就提示read only。当不存在getter时,就提示not defined。
好了,落成一个__set了,后面可比这个轻松多了,因为很多根蒂根基在这里讲掉了,所以,不消愁闷后面路漫漫。
__get
1 public function __get(¥name)
2 {
3 ¥getter=""get"".¥name;
4 if(method_exists(¥this,¥getter))
5 return ¥this->¥getter();
6 else if(strncasecmp(¥name,""on"",2)===0 && method_exists(¥this,¥name))
7 {
8 // duplicating getEventHandlers() here for performance
9 ¥name=strtolower(¥name);
10 if(!isset(¥this->_e[¥name]))
11 ¥this->_e[¥name]=new CList;
12 return ¥this->_e[¥name];
13 }
14 else if(isset(¥this->_m[¥name]))
15 return ¥this->_m[¥name];
16 else if(is_array(¥this->_m))
17 {
18 foreach(¥this->_m as ¥object)
19 {
20 if(¥object->getEnabled() && (property_exists(¥object,¥name) || ¥object->canGetProperty(¥name)))
21 return ¥object->¥name;
22 }
23 }
24 throw new CException(Yii::t(""yii"",""Property "{class}.{property}" is not defined."",
25 array(""{class}""=>get_class(¥this), ""{property}""=>¥name)));
26 }
有了__set的解析,这里就会很多,这里是5块,比__set多的一块,是用来获取behaivor的。咦,那为什么__set中没有写入behavior的操纵?为了更好的语义,在yii中选择没有写入behavior这个概念,只能经由过程attach,所以你要attach一个behavior,就用attachBehavior。熟悉打听了,这点,让我们持续看代码,这5块分别为,4-5行,6-13行,14-15行,16-23行,24-25行。
4-5行:看有没有getter,有的话就运行getter。
6-13行:若是是on开首的话,就返回¥_e中对应的项,若是没有就初始化一个CList并传回。
14-15行:若是在¥_m中存在雷同名称的内容,就返回之。(这个就是返回behavior的那个)。
16-23行:此处的断定和__set的14-21行的景象极其类似。在这里就不久不多解析了。
24-25行:异常处理惩罚。
__isset
1 public function __isset(¥name)
2 {
3 ¥getter=""get"".¥name;
4 if(method_exists(¥this,¥getter))
5 return ¥this->¥getter()!==null;
6 else if(strncasecmp(¥name,""on"",2)===0 && method_exists(¥this,¥name))
7 {
8 ¥name=strtolower(¥name);
9 return isset(¥this->_e[¥name]) && ¥this->_e[¥name]->getCount();
10 }
11 else if(is_array(¥this->_m))
12 {
13 if(isset(¥this->_m[¥name]))
14 return true;
15 foreach(¥this->_m as ¥object)
16 {
17 if(¥object->getEnabled() && (property_exists(¥object,¥name) || ¥object->canGetProperty(¥name)))
18 return true;
19 }
20 }
21 return false;
22 }
本来在PHP中isset主如果用于对变量是否存在作断定的,在这里yii将其的应用局限扩大了。感触感染更贴切的说isset变成了一个断定是否存在响应的getter(4-5行),对应的Event Handler是否含有真正的handler(6-10行),对应的behavior是否存在(11-20行)。这里须要重视下15-19行,这里使得,不仅仅可以断定behavior本身,包含其所属的属性和getter办法也是可以断定是否存在的。简单的懂得就是当isset感化于不存在的属性时,其变成了一个断定是否存在getter,event handler,behavior的办法。
__unset
1 public function __unset(¥name)
2 {
3 ¥setter=""set"".¥name;
4 if(method_exists(¥this,¥setter))
5 ¥this->¥setter(null);
6 else if(strncasecmp(¥name,""on"",2)===0 && method_exists(¥this,¥name))
7 unset(¥this->_e[strtolower(¥name)]);
8 else if(is_array(¥this->_m))
9 {
10 if(isset(¥this->_m[¥name]))
11 ¥this->detachBehavior(¥name);
12 else
13 {
14 foreach(¥this->_m as ¥object)
15 {
16 if(¥object->getEnabled())
17 {
18 if(property_exists(¥object,¥name))
19 return ¥object->¥name=null;
20 else if(¥object->canSetProperty(¥name))
21 return ¥object->¥setter(null);
22 }
23 }
24 }
25 }
26 else if(method_exists(¥this,""get"".¥name))
27 throw new CException(Yii::t(""yii"",""Property "{class}.{property}" is read only."",
28 array(""{class}""=>get_class(¥this), ""{property}""=>¥name)));
29 }
unset的感化就是开释资料,懂得了unset的目标,我们可以看看__unset做了哪些,
4-5行:当有setter存在的时辰,
1 public function __call(¥name,¥parameters)
2 {
3 if(¥this->_m!==null)
4 {
5 foreach(¥this->_m as ¥object)
6 {
7 if(¥object->getEnabled() && method_exists(¥object,¥name))
8 return call_user_func_array(array(¥object,¥name),¥parameters);
9 }
10 }
11 if(class_exists(""Closure"", false) && ¥this->canGetProperty(¥name) && ¥this->¥name instanceof Closure)
12 return call_user_func_array(¥this->¥name, ¥parameters);
13 throw new CException(Yii::t(""yii"",""{class} and its behaviors do not have a method or closure named "{name}"."",
14 array(""{class}""=>get_class(¥this), ""{name}""=>¥name)));
15 }
这段代码,起首断定了¥_m是不是为空,这个¥_m