php有一類很神奇的方法,這些方法是保留方法,通常不會在外部被顯式調用,他們使用雙下劃線(__)開頭,他們被稱為魔術方法(Magic Methods)。php官方也不建議定義其他雙下劃線開頭的方法。
這次介紹最常見的魔術方法:構造函數和析構函數。
1. 構造函數(__construct)
void __construct ([ mixed $args [, $... ]] )
構造函數:擁有構造函數的類會在每次創建新對象時先調用此方法,所以非常適合在使用對象前做一些初始化服務。
注意:
1. clone並不會調用構造函數
2. 如果子類定義了構造函數,則不會隱式調用父類的構造函數
3. 子類的構造函數允許和父類的構造函數參數不一致
4. 如果子類沒有定義構造函數,php會嘗試尋找父類的構造函數
5. 如果父類沒有定義構造函數,使用parent關鍵字顯式調用父類構造函數,會導致致命錯誤
1 <?php
2
3 class P{
4
5 public function __construct(){
6 echo __CLASS__ . "\n";
7 }
8
9 }
10
11 class C1 extends P{
12
13 public function __construct(){
14 echo __CLASS__ . "\n";
15 }
16
17 }
18
19 class C2 extends P{
20
21 public function __construct(){
22 parent::__construct();
23 echo __CLASS__ . "\n";
24 }
25
26 }
27
28 class C3 extends P{
29
30 }
31
32 // P
33 $ins = new P();
34
35 // Nothing
36 $ins2 = clone $ins;
37
38 // C1
39 new C1();
40
41 // P
42 // C2
43 new C2();
44
45 // P
46 new C3();
除了魔術方法的構造函數,php還支持與類名相同的構造函數,不過優先級比魔術方法低:
1 <?php
2
3 class C1{
4
5 public function C1(){
6 echo __CLASS__ . "1\n";
7 }
8
9 public function __construct(){
10 echo __CLASS__ . "2\n";
11 }
12
13 }
14
15 class C2{
16
17 public function C2(){
18 echo __CLASS__ . "1\n";
19 }
20
21 }
22
23 class C3{
24
25 public function C3(){
26 echo __CLASS__ . "1\n";
27 }
28
29 public function __construct(){
30 echo __CLASS__ . "2\n";
31 $this->C3();
32 }
33
34 }
35
36 // C12
37 new C1();
38
39 // C21
40 new C2();
41
42 // C32
43 // C31
44 new C3();
php5.3.3之後,在命名空間之內使用與類名同名的方法,不再作為構造函數,命名空間之外不變:
1 <?php
2
3 namespace N;
4
5 class C{
6
7 public function C(){
8 echo __CLASS__ . "\n";
9 }
10
11 }
12
13 // Nothing
14 new \N\C();
構造函數可以用全部三個訪問控制修飾符,如單例模式:
1 <?php
2
3 class Single{
4
5 public static function getInstance(){
6 static $ins = null;
7 if(empty($ins)){
8 $ins = new self();
9 }
10 return $ins;
11 }
12
13 private function __construct(){
14 echo __CLASS__ . "\n";
15 }
16
17 }
18
19 // Single
20 Single::getInstance();
2. 析構函數(__destruct)
void __destruct ( void )
析構函數:析構函數會在某個對象的引用被全部刪除或對象被顯示銷毀時執行。
注意:
1. 同構造函數類似,父類的析構函數並不會被引擎暗中調用,必須顯式調用parent::__destruct
2. exit和die並不能阻止析構函數的執行
3. 致命錯誤會阻止析構函數的執行
4. 在析構函數中調用exit,可以阻止其他未執行的析構函數的執行
5. 如果父類沒有定義析構函數,使用parent關鍵字顯式調用父類析構函數,會導致致命錯誤
<?php
class P{
function __destruct(){
echo get_class($this) . "\t" . __CLASS__ . "\n";
}
}
class C1 extends P{
function __destruct(){
echo get_class($this) . "\t" . __CLASS__ . "\n";
}
}
class C2 extends P{
function __destruct(){
parent::__destruct();
echo get_class($this) . "\t" . __CLASS__ . "\n";
}
}
class C3 extends P{
}
$insP = new P();
$ins1 = new C1();
$ins2 = new C2();
$ins3 = new C3();
/**
輸出:
C3 P
C2 P
C2 C2
C1 C1
P P
**/