php面向物件之過載(overloading)
在java中,過載就是函式或者方法有相同的名稱,但是引數列表不相同的情形,這樣的同名不同引數的函式或者方法之間,互相稱之為過載函式或者方法,這也牽涉到了多型。
在PHP中呢,有人說php沒有多型,那過載呢?
PHP所提供的"過載"(overloading)是指動態地"建立"類屬性和方法,分為屬性的過載和方法的過載;
我們是通過魔術方法(magic methods)來實現的,當呼叫當前環境下未定義或不可見的類屬性或方法時,過載方法會被呼叫。本節後面將使用"不可訪問屬性(inaccessible properties)"和"不可訪問方法(inaccessible methods)"來稱呼這些未定義或不可見的類屬性或方法。
屬性過載
public void __set ( string $name , mixed $value )
public mixed __get ( string $name )
public bool __isset ( string $name )
public void __unset ( string $name )
在給不可訪問的屬性賦值時,__set() 會被呼叫。
讀取不可訪問的屬性的值時,__get()會被呼叫。
當判斷不可訪問的屬性是否存在的時候(使用isset(),empty())時,__isset()會被呼叫。
當對不可訪問的屬性執行銷燬操作(unset())的時候,__unset()會被呼叫。
__get()方法,有兩個引數,$name是指要操作的變數名稱(另外三個都是這個意思),$value是指對應name的值。
一個很簡單的例子:
結果如下:class Person { public $name; private $age; public function __set($name, $value) { echo "你賦值的屬性{$name}不存在"; } public function __get($name) { echo "你所訪問的屬性{$name}不存在"; } public function __isset($name) { echo "你判斷的屬性{$name}不存在"; } public function __unset($name) { echo "你銷燬的屬性{$name}不存在"; } } $person = new Person(); echo '賦值操作:',$person->gender = 'nale',<br />'; echo '取值操作:',$person->gender,'<br />'; echo 'isset判斷操作:',isset($person->gender),'<br />'; echo 'empty判斷操作:',empty($person->gender),'<br />'; echo 'empty判斷操作:',empty($person->gender),'<br />'; echo 'unset操作:';unset($person->gender);
empty這裡後面有個1是因為當前返回的是true,輸出來就是1了;
當然,大家也會發現,沒有這些魔術方法,我照樣可以跑通,我把這些魔術方法註釋掉:
class Person {
public $name;
private $age;
// public function __set($name, $value)
// {
// echo "你賦值的屬性{$name}不存在";
// }
//
// public function __get($name)
// {
// echo "你所訪問的屬性{$name}不存在";
// }
//
// public function __isset($name)
// {
// echo "你判斷的屬性{$name}不存在";
// }
//
// public function __unset($name)
// {
// echo "你銷燬的屬性{$name}不存在";
// }
//
// public function __call($name, $arguments)
// {
// echo '你在呼叫不存在的方法';
// }
}
$person = new Person();
echo '賦值操作:',$person->gender = 123,'<br />';
echo '取值操作:',$person->gender,'<br />';
echo 'isset判斷操作:',isset($person->gender),'<br />';
echo 'empty判斷操作:',empty($person->gender),'<br />';
echo 'empty判斷操作:',empty($person->gender),'<br />';
echo 'unset操作:';unset($person->gender);
echo '取值操作:',$person->gender,'<br />'; //訪問不存在的屬性,因為被銷燬了,應該會報一個notic級別的錯誤
執行如下所示:
這個是因為在PHP中,並沒有強制屬性都在類中宣告,這是動態的給物件屬性賦值,在其它強型別語言中,可能行不通,所以在一般時候,並不建議這樣寫。
那如果有這種動態增加值的需求的時候怎麼辦呢,我們可以利用屬性的過載來完成,如下:
class Person {
public $name;
private $age;
private $_attr = array();
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
public function __get($name)
{
if($this->_attr[$name]){
return $this->_attr[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
$this->_attr[$name] = $value;
}
public function __isset($name)
{
return isset($this->_attr[$name]);
}
public function __unset($name)
{
unset($this->_attr[$name]);
}
}
$person = new Person('lightWay', 24);
//賦值操作
$person->gender = 'male';
$person->home = 'hubei';
echo $person->home; //取值操作
unset($person->home); //銷燬操作
方法過載
public mixed __call ( string $name , array $arguments )
public static mixed __callStatic ( string $name , array $arguments )
在物件中呼叫一個不可訪問方法時,__call() 會被呼叫。
在靜態上下文中呼叫一個不可訪問方法時,__callStatic() 會被呼叫。
$name 引數是要呼叫的方法名稱。$arguments 引數是一個列舉陣列,包含著要傳遞給方法 $name 的引數。
上程式碼說明吧:
class Person {
public function __call($name, $arguments)
{
echo '您正在呼叫一個不存在的方法',self::class,'::',$name,PHP_EOL;
print_r($arguments);
}
public static function __callStatic($name, $arguments)
{
echo '您正在呼叫一個不存在的靜態方法',self::class,'::',$name,PHP_EOL;
print_r($arguments);
}
}
$person = new Person();
$person->sayMyInfo1('123',2,true);
$person::show(1,2,3);
執行結果如下:
我們可以用PHP中的過載,去模擬其他語言中的過載,程式碼如下:
class Person {
public $name;
public function __construct($name)
{
$this->name = $name;
}
public function __call($name, $arguments)
{
if($name == 'eating') {
switch (count($arguments)) {
case 1 :
echo "{$this->name}正在用{$arguments[0]}吃中餐",PHP_EOL;
break;
case 2 :
echo "{$this->name}正在用{$arguments[0]}和{$arguments[1]}吃西餐",PHP_EOL;
break;
case 0:
default:
echo "{$this->name}在喝西北風",PHP_EOL;
break;
}
} else {
echo '您訪問的方法不存在';
}
}
}
$my = new Person('lightWay');
$my->eating('筷子');
$my->eating('刀','叉子');
$my->eating();
執行結果如下:
這裡只是用了引數的不同,來執行不同的動作,可以利用的點很多,很多框架都會到這個,好吧,這裡就完了,看完了,你還覺得PHP沒用多型嗎?