//定义抽象类'HTMLElement'
abstract class HTMLElement{
protected $attributes;
protected function __construct($attributes){
if(!is_array($attributes)){
throw new Exception('Invalid attribute type');
}
$this->attributes=$attributes;
}
// 抽象的'getHTML()'方法
abstract protected function getHTML();
}
//定义具体的类'Div'-扩展HTMLElement
class Div extends HTMLElement{
private $output='<div ';
private $data;
public function __construct($attributes=array(),$data){
parent::__construct($attributes);
$this->data=$data;
}
//'getHTML()'方法的具体实现
public function getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</div>';
return $this->output;
}
}
//定义具体类'Header1'-扩展HTMLElement
class Header1 extends HTMLElement{
private $output='<h1 ';
private $data;
public function __construct($attributes=array(),$data){
parent::__construct($attributes);
$this->data=$data;
}
//'getHTML()'方法的具体的实现
public function getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</h1>';
return $this->output;
}
}
//定义具体类'Paragraph'-扩展HTMLElement
class Paragraph extends HTMLElement{
private $output='<p ';
private $data;
public function __construct($attributes=array(),$data){
parent::__construct($attributes);
$this->data=$data;
}
//'getHTML()'方法的具体实现
public function getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</p>';
return $this->output;
}
}
//定义具体类'UnorderedList'-扩展HTMLElement
class UnorderedList extends HTMLElement{
private $output='<ul ';
private $items=array();
public function __construct($attributes=array(),$items=array()){
parent::__construct($attributes);
if(!is_array($items)){
throw new Exception('Invalid parameter for list items');
}
$this->items=$items;
}
//'getHTML()'方法的具体实现
public function getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
foreach($this->items as $item){
$this->output.='<li>'.$item.'</li>';
}
$this->output.='</ul>';
return $this->output;
}
}
如你所见,上面的(X)HTML widget类在生成一个网面中特定的元素时是非常有用的,但是我有意地把每一个类的代码写成这样,这样它们就不能够验证输入参数的有效性。你可能已经想到,输入参数将直接被传递到类构造器中并且作为属性赋值。问题出现了:这样做有什么错误吗?是的,有。现在,我将定义我的最简单的页面生成器类,并且用这样一些widget来填充(feed)它,这样你就可以看到这个类的输入是如何与不正确的对象相混杂。下面是该页面生成器类的签名:
class PageGenerator{
private $output='';
private $title;
public function __construct($title='Default Page'){
$this->title=$title;
}
public function doHeader(){
$this->output='<html><head><title>'.$this-
>title.'</title></head><body>';
}
public function addHTMLElement($htmlElement){
$this->output.=$htmlElement->getHTML();
}
public function doFooter(){
$this->output.='</body></html>';
}
public function fetchHTML(){
return $this->output;
}
}
现在,我们开始实例化一些(X)HTML widget对象,并且把它们传递到相应的生成器类,如下面的示例所示:
try{
//生成一些HTML元素
$h1=new Header1(array('name'=>'header1','class'=>'headerclass'),'Content for H1
element goes here');
$div=new Div(array('name'=>'div1','class'=>'divclass'),'Content for Div element
goes here');
$par=new Paragraph(array('name'=>'par1','class'=>'parclass'),'Content for Paragraph
element goes here');
$ul=new UnorderedList(array ('name'=>'list1','class'=>'listclass'),array
('item1'=>'value1','item2'=>'value2','item3'=>'value3'));
//实例化页面生成器类
$pageGen=new Page生成器();
$pageGen->doHeader();
// 添加'HTMLElement'对象
$pageGen->addHTMLElement($h1);
$pageGen->addHTMLElement($div);
$pageGen->addHTMLElement($par);
$pageGen->addHTMLElement($ul);
$pageGen->doFooter();
//显示网面
echo $pageGen->fetchHTML();
}
catch(Exception $e){
echo $e->getMessage();
exit();
}
在运行上面的PHP代码后,你所得到的结果是一个简单的网页-它包含一些前面创建的(X)HTML对象。这种情况下,如果因某些原因该网页生成器类收到一个不正确的对象并调用它的"addHTML()"方法,那么你很容易理解将会发生的事情。在此,我重新修改了这里的冲突条件-通过使用一个不存在的(X)HTML widget对象。请再次看一下下面的代码:
try{
//生成一些HTML元素
$h1=new Header1(array('name'=>'header1','class'=>'headerclass'),'Content for H1
element goes here');
$div=new Div(array('name'=>'div1','class'=>'divclass'),'Content for Div element
goes here');
$par=new Paragraph(array('name'=>'par1','class'=>'parclass'),'Content for Paragraph
element goes here');
$ul=new UnorderedList(array ('name'=>'list1','class'=>'listclass'),array
('item1'=>'value1','item2'=>'value2','item3'=>'value3'));
//实例化页面生成器类
$pageGen=new Page生成器();
$pageGen->doHeader();
//添加'HTMLElement'对象
$pageGen->addHTMLElement($fakeobj) //把并不存在的对象传递
到这个方法
$pageGen->addHTMLElement($div);
$pageGen->addHTMLElement($par);
$pageGen->addHTMLElement($ul);
$pageGen->doFooter();
// 显示网面
echo $pageGen->fetchHTML();
}
catch(Exception $e){
echo $e->getMessage();
exit();
}
在这种情况中,如下面一行所显示的:
Fatal error: Call to a member function on a non-object in
path/to/file
怎么样?这就是对传递到生成器类的对象的类型不进行检查的直接惩罚!因此在编写你的脚本时一定要记住这个问题。幸好,还有一个简单的方案来解决这些问题,而且这也正是"instanceof"操作符的威力所在。如果你想要看一下这个操作符是如何使用的,请继续往下读吧。 三、 使用"instanceof"操作符
如你所见,"instanceof"操作符的使用非常简单,它用两个参数来完成其功能。第一个参数是你想要检查的对象,第二个参数是类名(事实上是一个接口名),用于确定是否这个对象是相应类的一个实例。当然,我故意使用了上面的术语,这样你就可以看到这个操作符的使用是多么直观。它的基本语法如下:
if (object instanceof class name){
//做一些有用的事情
}
现在,既然你已经了解了这个操作符在PHP 5是如何使用的,那么,为了验证被传递到它的"addHTMLElement()"方法的对象的类型,让我们再定义相应的网页生成器类。下面是这个类的新的签名,我在前面已经提到,它使用了"instanceof"操作符:
class PageGenerator{
private $output='';
private $title;
public function __construct($title='Default Page'){
$this->title=$title;
}
public function doHeader(){
$this->output='<html><head><title>'.$this->title.'</title></head><body>';
}
public function addHTMLElement($htmlElement){
if(!$htmlElement instanceof HTMLElement){
throw new Exception('Invalid (X)HTML element');
}
$this->output.=$htmlElement->getHTML();
}
public function doFooter(){
$this->output.='</body></html>';
}
public function fetchHTML(){
return $this->output;
}
}
请注意,在上面的类中,为了确定所有传递的对象是早些时候定义的"HTMLElement"类的实例,"instanceof"操作符是如何包含在"addHTMLElement()"方法中的。现在,有可能重新构建你前面看到的网页,在这种情况下,请确保所有的传递到该网页生成器类的输入对象都是真正的(X)HTML widget对象。下面是相应示例:
try{
//生成一些HTML元素
$h1=new Header1(array('name'=>'header1','class'=>'headerclass'),'Content for H1 element goes here');
$div=new Div(array('name'=>'div1','class'=>'divclass'),'Content for Div element goes here');
$par=new Paragraph(array('name'=>'par1','class'=>'parclass'),'Content for Paragraph element goes here');
$teststr='This is not a HTML element';
//实例化页面生成器类
$pageGen=new Page生成器();
$pageGen->doHeader();
//添加'HTMLElement'对象
$pageGen->addHTMLElement($teststr) //把简单的字符串传递到这个方法
$pageGen->addHTMLElement($h1);
$pageGen->addHTMLElement($div);
$pageGen->addHTMLElement($par);
$pageGen->doFooter();
//显示网页
echo $pageGen->fetchHTML();
}
catch(Exception $e){
echo $e->getMessage();
exit();
}
正如你在上面的示例已经看到的,我把一个简单的测试用字符串(并不是一个"HTMLElement"对象)传递到该页面生成器类中,这将通过addHTMLElement()"方法抛出一个异常-为特定的"catch"块所捕获,如下所示:
Invalid (X)HTML element
此时,为了确定输入对象的有效性,我使用了"instanceof"操作符,这样以来,可以把上面的网页生成器类转换成一部分更为有效的代码片断。我希望你能真正体会到,通过使用这个操作符,对你的类的方法的输入进行过滤的极端重要性,这样就可以免除外来的不正确的数据输入。
在展示了"instanceof"操作符在网页生成器类内的正确实现后,还有更多的事情要做。类似于我在前面一篇文章中为PHP 4所编写的(X)HTML widget类,我想包含这个操作符作为它们的"getHTML()"方法的一部分,这样就可以允许创建生成嵌套的(X)HTML元素的网页。下面,让我们讨论这是如何实现的。
<?php
//定义一个抽像类HTMLElement
abstract class HTMLElement
{
protected $attributes;
protected function __construct($_attributes)
{
if(!is_array($_attributes))
{
throw new Exception("attributes not is array");
}
$this->attributes = $_attributes;
}
//定义一个虚函数
abstract function getHTML();
}
//定义具体的类"Div"扩展HTMLElement
class Div extends HTMLElement
{
private $_output = "<div";
private $_data;
public function __construct($_attributes=array(), $data)
{
//扩展"instanceof"操作符的使用:嵌套(X)HTML widget
if(!$data instanceof HTMLElement && !is_string($data)) {
throw new Exception("data type error");
}
parent::__construct($_attributes);
$this->_data = $data;
}
public function getHTML()
{
foreach ($this->attributes as $key=>$val)
{
$this->_output.= " ".$key."='".$val."' ";
}
$this->_output =substr_replace($this->_output,">",-1);
$this->_output .= $this->_data instanceof HTMLElement ? $this->_data->getHTML()."</div>" : $this->_data."</div>";
return $this->_output;
}
}
//定义具体的类"H1"扩展
class h1 extends HTMLElement
{
private $_output="<h1";
private $_data;
public function __construct($_attributes=array(), $data)
{
parent::__construct($_attributes);
$this->_data = $data;
}
public function getHTML()
{
foreach($this->attributes as $key=>$val)
{
$this->_output.= " ".$key."='".$val."' ";
}
$this->_output = substr_replace($this->_output, ">", -1);
$this->_output .= $this->_data."<h1>";
return $this->_output;
}
}
//定义具体的类"ul"
class ul extends HTMLElement
{
public $output = "<ul";
private $ulitem=array();
public function __construct($_attributes=array(), $_ulitem=array())
{
parent::__construct($_attributes);
$this->ulitem = $_ulitem;
}
public function getHTML()
{
foreach($this->attributes as $key=>$val)
{
$this->_output.= " ".$key."='".$val."' ";
}
$this->output = substr_replace($this->output, ">",-1);
foreach($this->ulitem as $ukey=>$uval){
$this->output .="<li>".$uval."</li>";
}
$this->output.="</ul>";
return $this->output;
}
}
//生成页面的类
class PageGenerator
{
private $_output;
private $_title;
public function __construct($title=" Default page")
{
$this->_title = $title;
}
public function doHead()
{
$this->_output.="<html><head><title>".$this->_title."</title></head><body>";
}
//public function addHTMLElement($HTMLElement)
//{
//$this->_output.= $HTMLElement->getHTML();
//}
//对addHTMLElement进行改进
//可以保证传入的不是HTMLElement类对像直接报错
public function addHTMLElement($HTMLElement)
{
if(!$HTMLElement instanceof HTMLElement)
{
throw new Exception('Invalid (X)HTML element');
}
$this->_output.= $HTMLElement->getHTML();
}
public function doFooter()
{
$this->_output.="</body></html>";
}
public function fetchHTML()
{
return $this->_output;
}
}
try{
$attribute = array("class"=>"className", "style"=>"color:#000");
$h1 = new H1($attribute, "h1内容");
$attribute = array("class"=>"className", "style"=>"color:#000");
$ul = new ul($attribute, array("li第一行内容","li第二行内容","li第三行内容"));