- ·上一篇文章:PHPUnit袖珍指南之安装PHPUnit
- ·下一篇文章:在PHP中开发XML应用程序之基础篇
PHP强制对象类型之instanceof操作符
一、简介
在PHP中实现强制对象类型有时可能非常重要。如果缺少了它,或是因为缺乏这方面的知识——基于不正确的编程假设,或者仅仅是由于懒惰,那么你会在特定的Web应用程序中看到你所不希望的结果。特别是当用PHP4进行编程时,使用"is_a()"函数(尽管还有其它方法)来验证你所使用的对象的类型是非常容易的事情。毫无疑问,强制对象类型还可以被用于过滤输入对象(需要被作为参数传递到同一个应用程序中的其它PHP类)。
不过,PHP4并没有暴露一些有关于它的对象模型的弱点-为了实现某些在成熟的面向对象的语言中出现的特征,它偶而可能要求编写另外的代码。长时间以来,这一事实已经为PHP社区众所周知。然而,随着PHP5的发行,许多这些极有价值的特征作为改进的对象模型的一部分被添加到其中。它们将有助于更为紧密地实现基于对象的代码的开发-允许你使用特定的对象特征。
在上面的情况下,当涉及到对象类型强制时应该特别注意。实际上,在一个Web应用程序的执行期间,PHP5提供给开发者至少两种方法来检查对象类型——它们分别是“instanceof”操作符和“类型提示”特征。现在转到本文的主题,我将介绍PHP5中"instanceof"操作符的使用;你很快就会发现,它可以非常方便地用来确定是否你正在使用的对象属于一个特定的类型。
本文将通过一些面向对象的示例来帮助你理解如何在PHP5中实现强制对象类型。
二、你不该做什么
为了展示在PHP5中如何实现对象类型强制,我将使用(X)HTMLwidget类,还有一个简单的页面生成器类,并作了简单的修改以适合PHP5开发环境。
我的第一个示例列举了一些派生自一个抽象的基类"HTMLElement"的(X)HTMLwidget类,它跳过了到它们的输入对象类型的检查。请先看下面的类:
//定义抽象类'HTMLElement'
abstractclassHTMLElement{
protected$attributes;
protectedfunction__construct($attributes){
if(!is_array($attributes)){
thrownewException('Invalidattributetype');
}
$this->attributes=$attributes;
}
//抽象的'getHTML()'方法
abstractprotectedfunctiongetHTML();
}
//定义具体的类'Div'-扩展HTMLElement
classDivextendsHTMLElement{
private$output='<div';
private$data;
publicfunction__construct($attributes=array(),$data){
parent::__construct($attributes);
$this->data=$data;
}
//'getHTML()'方法的具体实现
publicfunctiongetHTML(){
foreach($this->attributesas$attribute=>$value){
$this->output.=$attribute.'="'.$value.'"';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</div>';
return$this->output;
}
}
//定义具体类'Header1'-扩展HTMLElement
classHeader1extendsHTMLElement{
private$output='<h1';
private$data;
publicfunction__construct($attributes=array(),$data){
parent::__construct($attributes);
$this->data=$data;
}
//'getHTML()'方法的具体的实现
publicfunctiongetHTML(){
foreach($this->attributesas$attribute=>$value){
$this->output.=$attribute.'="'.$value.'"';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</h1>';
return$this->output;
}
}
//定义具体类'Paragraph'-扩展HTMLElement
classParagraphextendsHTMLElement{
private$output='<p';
private$data;
publicfunction__construct($attributes=array(),$data){
parent::__construct($attributes);
$this->data=$data;
}
//'getHTML()'方法的具体实现
publicfunctiongetHTML(){
foreach($this->attributesas$attribute=>$value){
$this->output.=$attribute.'="'.$value.'"';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</p>';
return$this->output;
}
}
//定义具体类'UnorderedList'-扩展HTMLElement
classUnorderedListextendsHTMLElement{
private$output='<ul';
private$items=array();
publicfunction__construct($attributes=array(),$items=array()){
parent::__construct($attributes);
if(!is_array($items)){
thrownewException('Invalidparameterforlistitems');
}
$this->items=$items;
}
//'getHTML()'方法的具体实现
publicfunctiongetHTML(){
foreach($this->attributesas$attribute=>$value){
$this->output.=$attribute.'="'.$value.'"';
}
$this->output=substr_replace($this->output,'>',-1);
foreach($this->itemsas$item){
$this->output.='<li>'.$item.'</li>';
}
$this->output.='</ul>';
return$this->output;
}
}
如你所见,上面的(X)HTMLwidget类在生成一个网面中特定的元素时是非常有用的,但是我有意地把每一个类的代码写成这样,这样它们就不能够验证输入参数的有效性。你可能已经想到,输入参数将直接被传递到类构造器中并且作为属性赋值。问题出现了:这样做有什么错误吗?是的,有。现在,我将定义我的最简单的页面生成器类,并且用这样一些widget来填充(feed)它,这样你就可以看到这个类的输入是如何与不正确的对象相混杂。下面是该页面生成器类的签名:
classPageGenerator{
private$output='';
private$title;
publicfunction__construct($title='DefaultPage'){
$this->title=$title;
}
publicfunctiondoHeader(){
$this->output='<html><head><title>'.$this-
>title.'</title></head><body>';
}
publicfunctionaddHTMLElement($htmlElement){
$this->output.=$htmlElement->getHTML();
}
publicfunctiondoFooter(){
$this->output.='</body></html>';
}
publicfunctionfetchHTML(){
return$this->output;
}
}
现在,我们开始实例化一些(X)HTMLwidget对象,并且把它们传递到相应的生成器类,如下面的示例所示:
try{
//生成一些HTML元素
$h1=newHeader1(array('name'=>'header1','class'=>'headerclass'),'ContentforH1
elementgoeshere');
$div=newDiv(array('name'=>'div1','class'=>'divclass'),'ContentforDivelement
goeshere
在PHP中实现强制对象类型有时可能非常重要。如果缺少了它,或是因为缺乏这方面的知识——基于不正确的编程假设,或者仅仅是由于懒惰,那么你会在特定的Web应用程序中看到你所不希望的结果。特别是当用PHP4进行编程时,使用"is_a()"函数(尽管还有其它方法)来验证你所使用的对象的类型是非常容易的事情。毫无疑问,强制对象类型还可以被用于过滤输入对象(需要被作为参数传递到同一个应用程序中的其它PHP类)。
不过,PHP4并没有暴露一些有关于它的对象模型的弱点-为了实现某些在成熟的面向对象的语言中出现的特征,它偶而可能要求编写另外的代码。长时间以来,这一事实已经为PHP社区众所周知。然而,随着PHP5的发行,许多这些极有价值的特征作为改进的对象模型的一部分被添加到其中。它们将有助于更为紧密地实现基于对象的代码的开发-允许你使用特定的对象特征。
在上面的情况下,当涉及到对象类型强制时应该特别注意。实际上,在一个Web应用程序的执行期间,PHP5提供给开发者至少两种方法来检查对象类型——它们分别是“instanceof”操作符和“类型提示”特征。现在转到本文的主题,我将介绍PHP5中"instanceof"操作符的使用;你很快就会发现,它可以非常方便地用来确定是否你正在使用的对象属于一个特定的类型。
本文将通过一些面向对象的示例来帮助你理解如何在PHP5中实现强制对象类型。
二、你不该做什么
为了展示在PHP5中如何实现对象类型强制,我将使用(X)HTMLwidget类,还有一个简单的页面生成器类,并作了简单的修改以适合PHP5开发环境。
我的第一个示例列举了一些派生自一个抽象的基类"HTMLElement"的(X)HTMLwidget类,它跳过了到它们的输入对象类型的检查。请先看下面的类:
abstractclassHTMLElement{
protected$attributes;
protectedfunction__construct($attributes){
if(!is_array($attributes)){
thrownewException('Invalidattributetype');
}
$this->attributes=$attributes;
}
//抽象的'getHTML()'方法
abstractprotectedfunctiongetHTML();
}
//定义具体的类'Div'-扩展HTMLElement
classDivextendsHTMLElement{
private$output='<div';
private$data;
publicfunction__construct($attributes=array(),$data){
parent::__construct($attributes);
$this->data=$data;
}
//'getHTML()'方法的具体实现
publicfunctiongetHTML(){
foreach($this->attributesas$attribute=>$value){
$this->output.=$attribute.'="'.$value.'"';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</div>';
return$this->output;
}
}
//定义具体类'Header1'-扩展HTMLElement
classHeader1extendsHTMLElement{
private$output='<h1';
private$data;
publicfunction__construct($attributes=array(),$data){
parent::__construct($attributes);
$this->data=$data;
}
//'getHTML()'方法的具体的实现
publicfunctiongetHTML(){
foreach($this->attributesas$attribute=>$value){
$this->output.=$attribute.'="'.$value.'"';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</h1>';
return$this->output;
}
}
//定义具体类'Paragraph'-扩展HTMLElement
classParagraphextendsHTMLElement{
private$output='<p';
private$data;
publicfunction__construct($attributes=array(),$data){
parent::__construct($attributes);
$this->data=$data;
}
//'getHTML()'方法的具体实现
publicfunctiongetHTML(){
foreach($this->attributesas$attribute=>$value){
$this->output.=$attribute.'="'.$value.'"';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</p>';
return$this->output;
}
}
//定义具体类'UnorderedList'-扩展HTMLElement
classUnorderedListextendsHTMLElement{
private$output='<ul';
private$items=array();
publicfunction__construct($attributes=array(),$items=array()){
parent::__construct($attributes);
if(!is_array($items)){
thrownewException('Invalidparameterforlistitems');
}
$this->items=$items;
}
//'getHTML()'方法的具体实现
publicfunctiongetHTML(){
foreach($this->attributesas$attribute=>$value){
$this->output.=$attribute.'="'.$value.'"';
}
$this->output=substr_replace($this->output,'>',-1);
foreach($this->itemsas$item){
$this->output.='<li>'.$item.'</li>';
}
$this->output.='</ul>';
return$this->output;
}
}
如你所见,上面的(X)HTMLwidget类在生成一个网面中特定的元素时是非常有用的,但是我有意地把每一个类的代码写成这样,这样它们就不能够验证输入参数的有效性。你可能已经想到,输入参数将直接被传递到类构造器中并且作为属性赋值。问题出现了:这样做有什么错误吗?是的,有。现在,我将定义我的最简单的页面生成器类,并且用这样一些widget来填充(feed)它,这样你就可以看到这个类的输入是如何与不正确的对象相混杂。下面是该页面生成器类的签名:
private$output='';
private$title;
publicfunction__construct($title='DefaultPage'){
$this->title=$title;
}
publicfunctiondoHeader(){
$this->output='<html><head><title>'.$this-
>title.'</title></head><body>';
}
publicfunctionaddHTMLElement($htmlElement){
$this->output.=$htmlElement->getHTML();
}
publicfunctiondoFooter(){
$this->output.='</body></html>';
}
publicfunctionfetchHTML(){
return$this->output;
}
}
现在,我们开始实例化一些(X)HTMLwidget对象,并且把它们传递到相应的生成器类,如下面的示例所示:
//生成一些HTML元素
$h1=newHeader1(array('name'=>'header1','class'=>'headerclass'),'ContentforH1
elementgoeshere');
$div=newDiv(array('name'=>'div1','class'=>'divclass'),'ContentforDivelement
goeshere
