PHP強制物件類型之instanceof運運算元(1)

日期:2006-09-28  作者:喜騰小二  來源:PHPChina


一、簡介

  在PHP中實現強制物件類型有時可能非常重要。如果缺少了它,或是因為缺乏這方麵的知識——基於不正確的編程假設,或者僅僅是由於懶惰,那麼妳會在特定的Web應用程式中看到妳所不希望的結果。特別是當用PHP
4進行編程時,使用"is_a()"函式(儘管還有其它方法)來驗證妳所使用的物件的類型是非常容易的事情。毫無疑問,強制物件類型還可以被用於篩選輸入物件(需要被作為參數傳遞到同一個應用程式中的其它PHP類)。

  不過,PHP
4並沒有暴露一些有關於它的物件模型的弱點-為了實現某些在成熟的麵嚮物件的語言中出現的特徵,它偶而可能要求編寫另外的程式碼。長時間以來,這一事實已經為PHP社區眾所周知。然而,隨着PHP
5的發行,許多這些極有價值的特徵作為改進的物件模型的一部分被新增到其中。它們將有助於更為緊密地實現基於物件的程式碼的開發-允許妳使用特定的物件特徵。

  在上麵的情況下,當涉及到物件類型強制時應該特別注意。實際上,在一個Web應用程式的執行期間,PHP
5提供給開發者至少兩種方法來檢查物件類型——它們分別是“instanceof”運運算元和“類型提示”特徵。現在轉到本文的主題,我將介紹PHP
5中"instanceof"運運算元的使用;妳很快就會發現,它可以非常方便地用來確定是否妳正在使用的物件屬於一個特定的類型。


  本文將透過一些麵嚮物件的範例來說明妳理解如何在PHP 5中實現強制物件類型。

  二、
妳不該做什麼


  為了展示在PHP 5中如何實現物件類型強制,我將使用(X)HTML
widget類,還有一個簡單的页面生成器類,並作了簡單的修改以適合PHP
5開發環境。

  我的第一個範例列舉了一些派生自一個抽象的基類"HTMLElement"的(X)HTML
widget類,它跳過了到它們的輸入物件類型的檢查。請先看下麵的類:

//定義抽象類'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();
}

  在這種情況中,如下麵一行所顯示的:

$pageGen->addHTMLElement($fakeobj)//把不存在的物件傳遞到這個方法

  一個並不存在的(X)HTML
widget物件被傳遞到該页面生成器類,這樣會導緻一個緻命性錯誤:

Fatal error: Call to a member function on a non-object
in
path/to/file

  怎麼樣?這就是對傳遞到生成器類的物件的類型不進行檢查的直接懲罰!因此在編寫妳的指令檔時一定要記住這個問題。幸好,還有一個簡單的方案來解決這些問題,而且這也正是"instanceof"運運算元的威力所在。如果妳想要看一下這個運運算元是如何使用的,請繼續往下讀吧。


<<<返回技術中心

技術文章

站內新聞

我要啦免费统计