PHP教學-多載(overload)魔術方法應用
物件導向中包含封裝、繼承、多型,其中以多型來講PHP也支援多載(重載)(overload)及覆寫(override),本篇是探討 PHP 多型中的重載( overload )。
PHP中的"多載"與其它絕大多數物件導向語言例如 JAVA、C++、C# 不同。傳統的"多載"是用於提供多個同名的類方法,但各方法的參數類型和個數不同。如果 PHP 也在類別中定義多個同名但方法和參數類型都不同,那麼會發生錯誤。
*使用在屬性多載的魔術方法
1. __set($name, $value):如果想要寫入物件無法存取的屬性,就會觸發這個方法
2. __get($name):如果想要讀取物件無法存取的屬性,就會觸發這個方法
3. __isset($name):如果想要用isset()或是empty()判斷物件所無法存取的屬性是否存在或為空,就會觸發這個方法
4. __unset($name):如果想要用unset()來清除物件無法存取的屬性,就會觸發這個方法
用一個最簡單的例子來看:
檢視原始檔複製到剪貼簿列印關於
<?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()都是類似的作用。
*使用在方法多載的魔術方法
1. __call($name, $args) :呼叫了物件未定義或無法存取的方法時觸發,$name是呼叫的方法名,$args是參數陣列
2. __callStatic($name, $args) (php5.3~) :呼叫了物件未定義或無法存取的靜態方法時觸發,$name是呼叫的方法名,$args是參數陣列
簡單的例子:
檢視原始檔複製到剪貼簿列印關於
<?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的多載跟別人不太一樣,但是用對地方的話就很對頭。
PHP中的"多載"與其它絕大多數物件導向語言例如 JAVA、C++、C# 不同。傳統的"多載"是用於提供多個同名的類方法,但各方法的參數類型和個數不同。如果 PHP 也在類別中定義多個同名但方法和參數類型都不同,那麼會發生錯誤。
*使用在屬性多載的魔術方法
1. __set($name, $value):如果想要寫入物件無法存取的屬性,就會觸發這個方法
2. __get($name):如果想要讀取物件無法存取的屬性,就會觸發這個方法
3. __isset($name):如果想要用isset()或是empty()判斷物件所無法存取的屬性是否存在或為空,就會觸發這個方法
4. __unset($name):如果想要用unset()來清除物件無法存取的屬性,就會觸發這個方法
用一個最簡單的例子來看:
檢視原始檔複製到剪貼簿列印關於
<?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()都是類似的作用。
*使用在方法多載的魔術方法
1. __call($name, $args) :呼叫了物件未定義或無法存取的方法時觸發,$name是呼叫的方法名,$args是參數陣列
2. __callStatic($name, $args) (php5.3~) :呼叫了物件未定義或無法存取的靜態方法時觸發,$name是呼叫的方法名,$args是參數陣列
簡單的例子:
檢視原始檔複製到剪貼簿列印關於
<?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的多載跟別人不太一樣,但是用對地方的話就很對頭。
留言
張貼留言