印象中PHP是從PHP4開始有OOP的特性,但是這些要到PHP5才夠完整。基本上在PHP5,類別(class)、介面(interface)、繼承(inheritance: extends/implements)、可視性(visibility)、覆載(overriding)、建構式(constructor)、解構式(destructor)等概念跟一般的Classical OOP大同小異,比較有不同的是多載(overloading)。
多載是實作多型的一種方式,以Java為例,某個class可能會有數種同名的方法,但是會有不同型別或數量的參數作為識別。當傳遞的參數型別符合時,就可以成功呼叫這個方法。不過在PHP中,多載長得不太一樣
參考:PHP:Overloading - Manual
PHP把多載定義為「動態」定義的方法或屬性...這跟Java的method overloading的概念不太一樣,所以如果用Java的概念來理解,就會有很大的誤會(我就犯過這樣的錯誤)。
在PHP中,有幾個**魔術方法(magic methods)**跟多載相關,包括:
*使用在屬性多載的魔術方法
用一個最簡單的例子來看:
<?php
class a {
function __get($name) {
if($name==='var1') return 'abc';
}
}
$a = new a;
echo $a->var1."\n";
echo $a->var2."\n";
class b {
private $var1 = 'abc';
private $var2 = 'def';
function __get($name) {
switch($name) {
case 'var1':
return $this->var1;
break;
case 'var2':
return 'ghi';
break;
}
}
}
$b = new b;
echo $b->var1."\n";
echo $b->var2."\n";
class c {}
$c = new c;
echo $c->var1."\n";
執行結果是:
Feng-Hsu-Pingteki-MacBook-Air:ironman6 fillano$ php 1-1a.php
abc
abc
ghi
PHP Notice: Undefined property: c::$var1 in /Users/fillano/builds/ironman6/1-1a.php on line 34
可以看出,只要是物件未定義或是無法存取的屬性,在讀取時就會會觸發這個方法。如果連這個方法都沒定義,就只好報錯。__set()、__isset()、__unset()都是類似的作用。
*使用在方法多載的魔術方法
簡單的例子:
<?php
class a {
function __call($name, $args) {
echo $name . " : " . print_r($args, true) . "\n";
}
}
$a = new a;
$a->func1('abc', 'def');
class b {
function __call($name, $args) {
switch($name) {
case 'add':
if(count($args)===2) {
if(is_numeric($args[0]) && is_numeric($args[1]))
return $args[0]+$args[1];
if(is_string($args[0]) && is_string($args[1]))
return $args[0].$args[1];
}
default:
throw new Exception("[warning] b::$name method not found.\n");
}
}
}
$b = new b;
echo $b->add(2,3)."\n";
echo $b->add('hello', ' world.')."\n";
try {
echo $b->add(2, ' world.')."\n";
}
catch (Exception $e) {
echo $e->getMessage();
}
執行結果:
Feng-Hsu-Pingteki-MacBook-Air:ironman6 fillano$ php 1-1b.php
func1 : Array
(
[0] => abc
[1] => def
)
5
hello world.
[warning] b::add method not found.
這裡模擬了參數型別來判斷處理方式的多載,傳入兩個數字給add時,他會相加,傳入兩個字串時,會把字串接起來。但是傳給一個數字及一個字串,就會出現警告:找不到方法。
__callStatic跟__call類似,只是作用在使用::呼叫靜態方法時,這是從PHP5.3才有的魔術方法。
*用途???
PHP的多載,可以讓需要動態產生大量不同屬性或方法的物件時,處理更簡單。例如要開發ORM,使用物件對應到不同資料表的列時,我們實際上並不需要根據不同資料表的不同欄位來定義不同的類別,只要利用PHP的多載...然後在__get()、__call()等方法裡面檢查查詢的結果,並根據傳入的參數判斷要回傳的資料,操作起來感覺就好像不同的類別實例。(感謝大神的教導)
但是如果不是可以發揮這類集中處理的長處時,恐怕就需要評估一下了。因為這樣反而會讓一個方法太複雜,比較難維護與理解。
總之,PHP的多載跟別人不太一樣,但是用對地方的話就很對頭。