Notice: This article is working on progress!
本章將介紹PHP類.
現在,基本上每種語言都支援物件導向,當然PHP也不列外。
PHP在以前的版本不支援物件導向,但自從PHP4,包括PHP4之後開始支援了。本系列將以PHP5為例來描述物件導向的知識。在後面也將提及PHP4的知識。
PHP對物件導向的支援的能力,以我個人觀點,沒有C++,C#,Java等語言那麼深入,即使如此,也算得上是比較全面的。
你問問現在的每一個人物件導向的特點是什嗎?他們肯定回答封裝,多態,繼承,沒錯,就是這些。
類
好了,我們從類開始說起吧。類的概念不說了,世人都知道。
PHP中的類可以這樣寫:
class Page
{
}
?>
它定義了一個簡單的類Page,什麼都沒有。
你也可以定義屬性和方法,如下:
class Page
{
// 2 attributes
var $attribute1 ;
var $attribute2 ;
// 2 functions
function Operation1()
{
}
function Operation2( $param1 , $param2 )
{
}
}
?>
PHP的類有構造和解構函式嗎?答案是肯定的,有!那麼是不是和C++的一樣呢?不是,它有專門的函數。
構造用__construct();析構用__destruct();( 注意:前面是2個底線)
代碼如下:
1 2 class Page
3 {
4 // 2 attributes
5 var $attribute1 ;
6 var $attribute2 ;
7
8 // 2 functions
9 function Operation1()
10 {
11 }
12
13 function Operation2( $param1 , $param2 )
14 {
15 }
16
17 // construction function
18 function __construct( $param )
19 {
20 $this -> attribute1 = $param ;
21 }
22
23 // destruction function
24 function __destruct()
25 {
26 $this -> attribute1 = 0 ;
27 }
28 }
29 ?>
PHP支援重載嗎? 是的,PHP支援重載,這樣就可以有多種方式進行構造了。
類的執行個體化
構建了類,我們就需要應用它,如何使用?執行個體化,這個和其他語言一樣,所以只給出代碼:
1 2 class Page
3 {
4 // 2 attributes
5 var $attribute1 ;
6 var $attribute2 ;
7
8 // 2 functions
9 function Operation1()
10 {
11 }
12
13 function Operation2( $param1 , $param2 )
14 {
15 }
16
17 // construction function
18 function __construct( $param )
19 {
20 $this -> attribute1 = $param ;
21 echo " It will construct the attribute: {$this->attribute1}
" ;
22 }
23
24 // destruction function
25 function __destruct()
26 {
27 $this -> attribute1 = 0 ;
28 }
29 }
30 $instance1 = new Page( " attribute1 in instance 1 " );
31 $instance2 = new Page( " attribute2 in instance 2 " );
32 $instance1 = new Page();
33 ?>
輸出結果是:
1 It will construct the attribute : attribute1 in instance 1
2 It will construct the attribute : attribute2 in instance 2
3 It will construct the attribute :
設定或得到屬性
這個問題很有意思。
拿上面的例子來說, $attribute1 就是一個屬性,我們可以利用 $this -> attribute1 來擷取或設定其值。
但是為了更好的體現類的封裝性,還是採用PHP提供的get或set方法,這個和C#裡的功能這樣。但是在PHP中,提供2個方法:__get($name),__set($name,$value)函數來設定屬性。
這樣做的另外一個好處就是根據實際需要,加入自己的邏輯,如果直接賦值的話就不能辦到。比如說屬性一定要是1-100之間的數,怎麼辦?還是採用__set吧。看看代碼吧:
1 2 class Page
3 {
4 //2 attributes
5 var $attribute1;
6 var $attribute2;
7
8 //2 functions
9 function Operation1()
10 {
11 }
12
13 function Operation2($param1,$param2)
14 {
15 }
16
17 //construction function
18 function __construct($param)
19 {
20 $this->attribute1=$param;
21 echo "It will construct the attribute: {$this->attribute1}
";
22 }
23
24 //destruction function
25 function __destruct()
26 {
27 $this->attribute1=0;
28 }
29 function __set($name,$value)
30 {
31 if($name==="attribute2"&&$value>=2&&attribute2<=100)
32 {
33 $this->attribute2=$value;
34 }
35 }
36 function __get($name)
37 {
38 return $this->$name;
39 }
40 }
41 $instance1=new Page("attribute1 in instance 1");
42 $instance2=new Page("attribute1 in instance 1");
43 $instance3=new Page();
44 $instance3->attribute2=99;
45 echo $instance3->attribute2;
46 ?>
類成員和方法的可視性
還是public,private以及protected。和C#的作用一樣。但是需要注意的是,PHP預設的是public,而不是大多數語言預設的private。基於此,上述的例子才可以使用。還需要注意的一點是,如果使用了這3個關鍵字,var就省略了。看個例子吧。
1 2 class Page
3 {
4 //2 attributes
5 public $attribute1;
6 public $attribute2;
7
8 //2 functions
9 public function Operation1()
10 {
11 }
12
13 public function Operation2($param1,$param2)
14 {
15 }
16
17 //construction function
18 public function __construct($param)
19 {
20 $this->attribute1=$param;
21 echo "It will construct the attribute: {$this->attribute1}
";
22 }
23
24 //destruction function
25 public function __destruct()
26 {
27 $this->attribute1=0;
28 }
29 public function __set($name,$value)
30 {
31 if($name==="attribute2"&&$value>=2&&attribute2<=100)
32 {
33 $this->attribute2=$value;
34 }
35 }
36 public function __get($name)
37 {
38 return $this->$name;
39 }
40 }
41 $instance1=new Page("attribute1 in instance 1");
42 $instance2=new Page("attribute1 in instance 1");
43 $instance3=new Page();
44 $instance3->attribute2=99;
45 echo $instance3->attribute2;
46 ?>
類的繼承
類的繼承和C#,Java語言一樣,不支援多重繼承。PHP實用extends來繼承一個類,和Java有些類似。
在Java裡有final這個詞,PHP裡也有,並且作用相似,就是為了阻止繼承或重載,重寫方法。
提到繼承,那麼PHP支援介面嗎?支援。例如:
1 2 interface IDispose
3 {
4 function Dispose();
5 }
6
7 class page extends IDispose
8 {
9 function Dispose()
10 {
11 // Your code here.
12 }
13 }
14 ?>
PHP新的進階功能
1. Per-class常量
它是在PHP5引入的。這個常理不需要再初始化。例如:
1 2 class Math
3 {
4 const pi=3.1415927;
5 }
6 echo "Math::pi='.Math::pi."\n";
7 ?>
其實和C++裡的靜態變數一樣。
2. 靜態函數
既然說到了靜態變數,當然也要說靜態函數了。它和上面的思想一樣,實現時需要加static關鍵字,好多語言都是這樣的。C#,Java等。
代碼可以如下:
1 2 class Shape
3 {
4 static function SquredSize($length)
5 {
6 return $length*$length;
7 }
8 }
9 echo "Squre:".Shape::SquredSize(10);
10 ?>
3. PHP 的類的類型檢查
你要想判斷一個類是不是某個類的類型。非常簡單,就是instanceof,如果你使用過java,那麼你非常熟悉了,因為和Java一樣。如果你是用C#的,類似於C# 裡的is。
4. 複製對象
PHP提供一個關鍵字,clone,就是這個功能。我看PHP是我見到語言中複製對象比較簡單的語言之一。代碼如下:
$c = clone $b
如果你想改變$c的某一特性,怎麼辦?這個時候你需要重寫__clone方法。
5. 抽象類別
PHP也支援抽象類別,並且和C#等語言非常類似。給個例子吧。
1 2 abstract class Shape
3 {
4 abstract protected function getSquared();
5 abstract protected function getLineCount();
6 public function printShapeValue()
7 {
8 echo "The squared size is :{$this->getSquared()}
";
9 echo "And the number of lines is :{$this->getLineCount()}
";
10 }
11 }
12
13 class Rectange extends Shape
14 {
15 protected function getSquared()
16 {
17 return 12*12;
18 }
19 protected function getLineCount()
20 {
21 return 4;
22 }
23 }
24
25 class Triangle extends Shape
26 {
27 protected function getSquared()
28 {
29 return 10*12;
30 }
31 protected function getLineCount()
32 {
33 return 3;
34 }
35 }
36
37 $rect=new Rectange();
38 $rect->printShapeValue();
39
40 $tri=new Triangle();
41 $tri->printShapeValue();
42 ?>
輸出的結果如下:
The squared size is : 144
And the number of lines is : 4
The squared size is : 120
And the number of lines is : 3
注意抽象函數的寫法,abstract關鍵字。以及在子類裡,沒有override關鍵字,而是直接重寫。這是和C#不同的。
6. 使用__call重載
這是我認為PHP提供的一個非常cool的功能,非常的佩服。這個方法用來監視一個對象中的其它方法。如果你試著調用一個對象中不存在的方法,__call 方法將會被自動調用。
舉個例子吧。代碼如下:
1 2 class Caller
3 {
4 private $x = array(1, 2, 3);
5
6 public function __call($m, $a)
7 {
8 print "Method $m called:\n";
9 var_dump($a);
10 return $this->x;
11 }
12 }
13
14 $foo = new Caller();
15 $a = $foo->test1(1, "2", 3.4, true);
16 var_dump($a);
17 ?>
顯示的結果如下:
Method test1 called : array ( 4 ) { [ 0 ] => int( 1 ) [ 1 ] => string ( 1 ) " 2 " [ 2 ] => float ( 3.4 ) [ 3 ] => bool( true ) } array ( 3 ) { [ 0 ] => int( 1 ) [ 1 ] => int( 2 ) [ 2 ] => int( 3 ) }
$foo->test1這個方法在foo類裡不存在的,但是定義了__call之後,就可以了。
7. 使用__autoload()方法。
這個功能仍然很cool。很多開發人員寫面向象的應用程式時對對每個類的定義建立一個 PHP 源檔案。一個很大的痛苦是不得不在每個指令碼(每個類一個檔案)開頭寫一個長長的包含檔案清單。在 PHP 5 中,我們再也不需要這樣了。 __autoload 函數就能輕鬆搞定,當程式碼檢視使用未定義的類時,此方法自動調用。通過調用此函數,指令碼引擎在出錯失敗之前就有了最後一個補救的機會來載入所需的類。但是需要注意的是 __autoload 函數拋出的異常不能被 catch 語句塊捕獲並導致致命錯誤。
一個例子:
1 2 function __autoload( $class_name ) {
3 require_once $class_name . ' .php ' ;
4 }
5
6 $obj1 = new MyClass1();
7 $obj2 = new MyClass2();
8 ?>
8,實現迭代期或迭代。
它將迭代類的所有可見的屬性以及值等
9 . 將類型轉化為字串(__toString()).
這是一個魔術函數的應用,__toString().它有點像C#裡的ToString()函數一樣,但是對於類本身來說還是有區別的。如果你在PHP的類裡實現了該函數,它們載列印這個類時就會調用此函數,例如:
1 2 class Page
3 {
4 public function __toString()
5 {
6 return ' Hello ' ;
7 }
8 }
9 $page = new Page();
10 echo $page ;
11 ?>
它將輸出:
Hello
10. 反射。
沒想到PHP也支援反射的。如果你對C#的反射熟悉的話,它們我就不用說了。如果不是,請繼續往下看。
反射是通過類或對象尋找它包含的內容的資訊的能力。當此類的文檔資訊不詳或沒有提供時,可以通過反射得到類的一些屬性,方法等資訊。
反射繼承了Zend的一些類。具體實用請參看PHP反射的類的文檔。