Yii는 컴포넌트 기반 웹 프레임워크이며, CComponent 클래스는 모든 컴포넌트의 기본 클래스입니다.
CComponent 클래스는 속성, 이벤트 및 동작을 기반으로 하는 프로그래밍 인터페이스가 있는 서브클래스를 제공합니다.
1. 컴포넌트 속성(property)
CcomComponent 클래스는 속성의 변수 저장을 제공하지 않으며, 이를 구현하려면 서브클래스에서 두 가지 메소드를 제공해야 합니다. 서브 클래스의 getPropertyName() 메소드는 $comComponent->PropertyName의 값 연산 데이터를 제공하고, 서브 클래스의 setPropertyName($val) 메소드는 $comComponent->PropertyName의 값 할당 연산을 제공합니다.
$width=$comComponent->textWidth;???? // textWidth 속성을 가져옵니다.
구현 방법은 $width=$comComponent- 서브 클래스에서 제공하는 메서드를 호출하는 것입니다. >getTextWidth( )
$comComponent->textWidth=$width;???? // textWidth 속성을 설정합니다
구현은 $comComponent 하위 클래스에서 제공하는 메서드를 호출하는 것입니다. ->setTextWidth($width )
public function getTextWidth() { return $this->_textWidth; } public function setTextWidth($value) { $this->_textWidth=$value; }
컴포넌트의 속성값은 대소문자를 구분하지 않습니다(클래스 멤버는 대소문자를 구분합니다)
2. events)
컴포넌트 이벤트는 이벤트 핸들러(함수명, 클래스 메소드, 객체 메소드 등)를 이벤트 이름에 등록(바인딩)하는 특수 속성으로, 다음과 같은 경우 핸들러가 자동으로 호출됩니다. 이벤트가 호출됩니다.
컴포넌트 이벤트는 CComponent의 $_e[] 배열에 저장됩니다. 배열의 키 값은 이벤트의 이름입니다. Clist는 Yii에서 제공하는 큐 컨테이너입니다. Clist의 add() 메소드는 이벤트의 콜백 핸들을 추가합니다.
//이벤트 처리에 전역 함수 추가
$comComponent-> onBeginRequest="logRequest";
//이벤트 처리에 클래스 정적 메서드 추가
$comComponent-> onBeginRequest=array("CLog"," logRequest");
//이벤트 처리에 객체 메서드 추가
$comComponent-> onBeginRequest=array($mylog," logRequest");
이벤트 발생:
$comComponent ->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($comComponent)는 자신을 구성 요소에 연결하고, detach($comComponent)는 $comComponent 연결을 제거하고, getEnabled() 및 setEnabled()는 동작 개체의 유효성을 설정합니다.
비헤이비어 개체는 구성 요소의 $_m[] 배열에 저장됩니다. 배열 키 값은 비헤이비어 이름 문자열이고 배열 값은 비헤이비어 클래스 개체입니다.
구성 요소는 attachmentBehavior($name,$behavior)를 통해 동작을 확장합니다.
$comComponent->attachBehavior('render',$htmlRender)
$comComponent에 렌더링 이름을 추가합니다. $htmlRender는 IBehavior 인터페이스를 구현하는 객체이거나 배열이어야 합니다.
array( ‘class’=>’path.to.BehaviorClass’, ‘property1′=>’value1′, ‘property2′=>’value2′, * )
은 동작 객체를 생성하고 배열의 클래스를 기반으로 속성 값을 설정합니다.
$htmlRender는 $_m['render']에 저장됩니다.
구성 요소의 정의되지 않은 메서드가 외부에서 호출되면 매직 메서드 __call()?은 모든 동작 개체를 순회하고 동일한 이름의 메서드가 발견되면 이를 호출합니다.
예를 들어 $htmlRender에는 구성 요소 메서드로 직접 액세스할 수 있는 renderFromFile() 메서드가 있습니다.
$comComponent-> 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)!