熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> PHP編程 >> 正文

PHP中實現面向對象編程

2022-06-13   來源: PHP編程 
  這篇文章介紹在PHP的面向對象編程(OOP)我將演示如何用面向對象的概念編出較少的代碼但更好的程序祝大家好運

  面向對象編程的概念對每一個作者來說都有不同的看法我提醒一下一個面向對象語言應有的東西
  (1)數據抽象和信息隱藏
  (2)繼承
  (3)多態性

  在PHP中使用類進行封裝的辦法

class Something {
// In OOP classes are usually named starting with a cap letter
var $x;

function setX($v) {
// Methods start in lowercase then use lowercase to seprate
// words in the method name example getValueOfArea()
$this>x=$v;
}

function getX() {
return $this>x;
}
}

?>

  當然你可以用你自己的辦法但有一個標准總是好的

  PHP中類的數據成員使用 var 定義數據成員是沒有類型直到被賦值一個數據成員可能是一個 integer數組聯合數組(associative array)或甚至對象(object) 方法在類裡定義成函數在方法裡存取數據成員你必須使用$this>name 這樣的辦法否則對方法來說是一個函數的局部變量

  使用 new 來創建一個對象

$obj = new Something;

  然後使用成員函數

$obj>setX();
$see = $obj>getX();

  setX 成員函數將 賦給對象(而不是類)obj 中成員變量 然後 getX 返回值

  你也可以用對象引用來存取成員變量例如$obj>x=; 然而這不一種好的面向對象編程的方法我堅持你應使用成員函數來設置成員變量的值和通過成員函數來讀取成員變量如果你認為成員變量是不可存取的除了使用成員函數的辦法你將成為一個好的面向對象程序員 但不幸的是PHP本身沒有辦法聲明一個變量是私有的所以允許糟糕的代碼存在

  在 PHP 中繼承使用 extend 來聲明

class Another extends Something {
 var $y;
 function setY($v) {
  // Methods start in lowercase then use lowercase to seperate
  // words in the method name example getValueOfArea()
  $this>y=$v;
 }

 function getY() {
  return $this>y;
 }
}

?>

  這樣類 Another 的對象擁有父類的所用成員變量及方法函數再加上自己的成員變量及成員函數

$obj=new Another;
$obj>setX();
$obj>setY();

  多重繼承不被支持所以你不能讓一個類繼承多個類

  在繼承類中你可以重新定義來重定義方法如果我們在 Another 重新定義 getX那麼我們不再能存取 Something 中的成員函數 getX 同樣如果我們在繼承類中聲明一個和父類同名的成員變量那麼繼承類的變量將隱藏父類的同名變量

  你可以定義一個類的構造函數 構造函數是和類同名的成員函數在你創建類的對象時被調用

class Something {
 var $x;

 function Something($y) {
  $this>x=$y;
 }

 function setX($v) {
  $this>x=$v;
 }

 function getX() {
  return $this>x;
 }
}

?>

  所以可以用如下方法創建對象

$obj=new Something();

  構造函數自動賦值 給成員變量 x 構造函數和成員函數都是普通的PHP函數所以你可以使用缺省參數

function Something($x=$y=)

  然後:

$obj=new Something(); // x= and y=
$obj=new Something(); // x= and y=
$obj=new Something(); // x= and y=

  缺省參數的定義方法和 C++ 一樣因此你不能傳一個值給 Y 但讓 X 取缺省值實參的傳遞是從左到右當沒有更多的實參時函數將使用缺省參數

  只有當繼承類的構造函數被調用後繼承類的對象才被創建父類的構造函數沒有被調用這是PHP不同其他面向對象語言的特點因為構造函數調用鏈是面向對象編程的特點如果你想調用基類的構造函數你不得不在繼承類的構造函數中顯式調用它這樣它能工作是因為在繼承類中父類的方法全部可用

function Another() {
$this>y=;
$this>Something(); //explicit call to base class constructor
}

?>

  在面向對象編程中一種好的機制是使用抽象類抽象類是一種不能實例化而是用來給繼承類定義界面的類設計師經常使用抽象類來強制程序員只能從特定的基類來繼承所以就能確定新類有所需的功能但在PHP中沒有標准的辦法做到這一點不過

  如果你在定義基類是需要這個特點可以通過在構造函數中調用 die這樣你就可以確保它不能實例化現在定義抽象類的函數並在每個函數中調用 die如果在繼承類中程序員不想重定義而直接調用基類的函數將會產生一個錯誤

  此外你需要確信因為PHP沒有類型有些對象是從基類繼承而來的繼承類創建的因此增加一個方法在基類來辨別類(返回 一些標識)並驗證這一點當你收到一個對象作為參數派上用場 但對於一個惡棍程序沒用辦法因為他可以在繼承類中重定義此函數通常這種辦法只對懶惰的程序員奏效當然最好的辦法是防止程序接觸到基類的代碼只提供界面

  重載在PHP中不被支持在面向對象編程中你可以通過定義不同參數種類和多少來重載一個同名成員函數PHP是一種松散的類型語言所以參數類型重載是沒有用的同樣參數個數不同的辦法重載也不能工作

  有時候在面向對象編程中重載構造函數很有用所以你能以不同的方式創建不同的對象(通過傳遞不同的參數個數)一個小巧門可以做到這一點

class Myclass {
function Myclass() {
$name=Myclassfunc_num_args();
$this>$name();
//Note that $this>$name() is usually wrong but here
//$name is a string with the name of the method to call
}

function Myclass($x) {
code;
}
function Myclass($x$y) {
code;
}
}

?>

  通過這種辦法可以部分達到重載的目的

$obj=new Myclass(); //Will call Myclass
$obj=new Myclass(); //Will call Myclass

  感覺還不錯!

  多態性

  多態性被定義為當在運行時刻一個對象作為參數傳遞時對象能決定調用那個方法的能力例如用一個類定義了方法 draw繼承類重定義 draw 的行為來畫圓或正方形這樣你就有一個參數為 x 的函數在函數裡可以調用$x>draw() 如果支持多態性那麼 draw 方法的調用就取決於對象 x 的類型多態性在PHP中很自然被支持(想一想這種情況在C++編譯器中如果編譯那一個方法被調用?然而你不知道對象的類型是什麼當然現在不是這種情況)

  幸好PHP支持多態性

function niceDrawing($x) {
//Supose this is a method of the class Board
$x>draw();
}

$obj=new Circle();
$obj=new Rectangle();

$board>niceDrawing($obj); //will call the draw method of Circle
$board>niceDrawing($obj); //will call the draw method of Rectangle

?>

  PHP的面向對象編程

  純對象論者認為PHP不是真正的面向對象語言這是對的PHP是一種混合語言你可以用面向對象或傳統結構編程的方法來使用它對於大型工程然而你可能或需要使用純面向對象方法來定義類並在你的工程中只使用對象和類越來越大的工程通過使用面向對象的方法會獲得益處面向對象工程非常容易維持容易理解並且重用這是軟件工程的基本使用這些概念在網站設計中是未來成功的關鍵

  PHP中的高級面向對象技術

  在回顧面向對象的基本概念之後我將介紹一些更高級的技術

  (1)串行化

  PHP並不支持持久性對象在面向對象語言中持久性對象是一些經過應用程序多次調用仍然保持其狀態和功能的對象這意味著有一種能保存對象到文件或數據庫中然後重新裝載對象這種機制稱之為串行化PHP 有一個串行化函數可以在對象中調用串行化函數返回一個字符串代表這個對象然後串行化函數保存的是成員數據而不是成員函數

  在PHP如果你串行化一個對象到字符串 $s 然後刪除此對象再反串行化對象到 $obj 你仍然可以調用對象的方法函數但我不推薦這種方法這因為(a)這種功能在將來不一定支持(b)這導致一種幻象如果你保存串行化對象到磁盤並退出程序將來重新運行此腳本時你不能反串行化此對象並希望對象的方法函數仍有效因為串行化出來的字符串並沒有表示任何成員函數最後串行化保存對象的成員變量在PHP中非常有用僅僅如此 (你可以串行化聯合數組和數組到磁盤裡)

  例子:

$obj=new Classfoo();
$str=serialize($obj);
// Save $str to disk

//some months later

//Load str from disk
$obj=unserialize($str)

?>

  上例中你可以恢復成員變量而沒有成員函數(根據文檔)這導致 $obj>x 是唯一的方法來存取成員變量(因為沒有成員函數)

  這裡還有一些方法解決這個問題但我沒留下給你因為它會搞髒這個干淨的文檔

  我希望PHP將來能全面支持串行化

  (2)使用類來操縱保存的數據

  PHP和面向對象編程中一個比較好的地方是你很容易定義類來操縱某些東西並且當需要時調用合適的類假設有一個HTML文件你需要通過選擇產品的ID號來選擇一個產品你的數據保存在數據庫中而你想顯示產品的信息如價格等等你有不同種類的產品同樣的動作對不同的產品有不同的含義

  例如顯示一個聲音意味著播放它而對其他產品來說可能是顯示一個存儲在數據庫的圖片你可以用面向對象編程和PHP來達到代碼少但更好

  定義一個類定義類應該有的方法然後通過繼承來定義每一種產品的類(SoundItem類 ViewableItem類等等)重定義每個產品類的方法使它們如你所需根據你保存在數據庫中的表的產品類型字段來給每一種產品類型定義一個類一個典型的產品表應有字段(id 類型 價格 描述等等)

  在腳本中你從數據庫的表中獲取類型信息然後實例化相應類的對象

$obj=new $type();
$obj>action();

?>

  這是PHP比較的特性你可以調用 $obj 的顯示方法或其他方法而不用去管對象的類型通過這種技術當你增加一種新類型的對象時你不需要去修改腳本這個方法有點威力就是定義所有對象應有的方法而不管它的類型然後在不同的類中以不同的方式來實現這樣就可以在腳本中對不同的類型對象使用他們再沒有 if 沒有兩個程序員在同一個文件裡永遠快樂你相信編程是這樣快樂不?維護代價小並且可重用?

  如果你帶領一組程序員最好的方法是劃分任務每人可以對某種類和對象負責國際化可以用同樣的技術解決使合適的類對應使用者選擇的不同的語言等等

  (3)復制和克隆

  當你創建一個對象 $obj 你可以使用 $obj = $obj 來拷貝一個對象新的對象是 $obj 的一個拷貝(不是引用)所以在賦值完新對象有 $obj 同新的狀態有時候你不想這樣只想創建和 obj 同樣的新對象調用新對象的構造函數如同你曾使用過 new 命令這可以通過PHP的串行化和使用基類並且其他類必須從基類繼承來達到

  (4)進行危險的地帶

  當你串行化一個對象你得到一個有特定格式的字符串如果你有好奇心可能你會探尋其中的秘密字符串中有一個東西就是類的名字你可以解開它

$herring=serialize($obj);
$vec=explode(:$herring);
$nam=str_replace(\\$vec[]);

?>

  假設你創建一個類 Universe 並且使所有類都從 Universe 繼承而來你可以在 Universe 定義一個克隆的方法:

class Universe {
 function clone() {
  $herring=serialize($this);
  $vec=explode(:$herring);
  $nam=str_replace(\\$vec[]);
  $ret=new $nam;
  return $ret;
 }
}

//Then:

$obj=new Something();
//Something extends Universe !!
$other=$obj>clone();

?>

  你所得的是類 Something 的新對象如同使用 new 一樣並且構造函數被調用等等我不知道這對你是不是有用這是一個很好的實踐Universe 類知道它的繼承類的名字對你來說唯一的限制是你的想象力!!!

  注意我使用的是PHP 文章裡有些東西可能不適合PHP


From:http://tw.wingwit.com/Article/program/PHP/201311/21517.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.