很多面試官在面試的時候都會問一些面向物件的問題,面向物件的三大特性中,多型最主要的實作方式就是方法的多載和重寫,但是在PHP中,只有重寫,并沒有完全的多載能力的實作,
重寫,子類重寫父類方法,
// 重寫
class A
{
public function test($a)
{
echo 'This is A:' . $a, PHP_EOL;
}
}
class childA extends A
{
public function test($a)
{
echo 'This is A child:' . $a, PHP_EOL;
}
}
$ca = new childA();
$ca->test(1);
這個在PHP中是沒有任何問題的,子類可以重寫父類的方法,當實體化子類的時候,呼叫的就是子類實作的重寫的方法,
多載,相同方法名但引數數量或者型別不同,
class A{
function foo($a){
echo $a;
}
// Fatal error: Cannot redeclare A::foo()
function foo($a, $b){
echo $a+$b;
}
}
抱歉,這樣寫的結果將會是直接的報錯,PHP并不支持這樣的多載能力,而在PHP的官方手冊上,多載的定義是使用__set()、__get()、__call()、__callStatic()等魔術方法來對無法訪問的變數或方法進行多載,這與我們所學習的面向物件中的多載完全不同,在手冊中的note里也有很多人對此提出了疑問,當然,我們今天并不會再去講這些魔術方法的使用,關于它們的使用可以參考我們之前寫過的文章:PHP中的那些魔術方法(一)、PHP的那些魔術方法(二)
那么,在PHP中可以實作多載嗎?當然可以,只不過會麻煩一些:
// 多載
class B
{
public function foo(...$args)
{
if (count($args) == 2) {
$this->fooAdd(...$args);
} else if (count($args) == 1) {
echo $args[0], PHP_EOL;
} else {
echo 'other';
}
}
private function fooAdd($a, $b)
{
echo $a + $b, PHP_EOL;
}
}
$b = new B();
$b->foo(1);
$b->foo(1, 2);
使用一個方法來呼叫其他方法,根據引數數量來進行判斷,就可以實作引數數量不同的方法多載,
// 使用__call()進行多載
class C
{
public function __call($name, $args)
{
if ($name == 'foo') {
$funcIndex = count($args);
if (method_exists($this, 'foo' . $funcIndex)) {
return $this->{'foo' . $funcIndex}(...$args);
}
}
}
private function foo1($a)
{
echo $a, PHP_EOL;
}
private function foo2($a, $b)
{
echo $a + $b, PHP_EOL;
}
private function foo3($a, $b, $c)
{
echo $a + $b + $c, PHP_EOL;
}
}
$c = new C();
$c->foo(1);
$c->foo(1, 2);
$c->foo(1, 2, 3);
使用__call()魔術方法或許會更簡單,但也會讓一些新手在接手專案的時候蒙圈,畢竟魔術方法對IDE是不友好的,這樣的開發讓__call()成為了一個模板方法,由它來定義操作的演算法骨架,我們也可以根據引數型別來模擬多載能力,
// 引數型別不同的多載
class D {
function __call($name, $args){
if($name == 'foo'){
if(is_string($args[0])){
$this->fooString($args[0]);
}else {
$this->fooInt($args[0]);
}
}
}
private function fooInt(int $a){
echo $a . ' is Int', PHP_EOL;
}
private function fooString(string $a){
echo $a . ' is String', PHP_EOL;
}
}
$d = new D();
$d->foo(1);
$d->foo('1');
不管怎么說,用上述方法實作的方法多載都非常麻煩,因為會讓某一個方法或者魔術方法非常重,它需要成為一個控制器來根據引數對內部的方法進行調度,更多的情況下,我們應該還是使用不同的方法名然后抽象公共的部分提取成獨立的私有內部方法來實作不同方法名的“多載”,畢竟不同的語言還是要掌握它們不同的個性,并且根據這些個性靈活地運用在我們的專案中,
測驗代碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/201912/source/PHP%E4%B8%AD%E7%9A%84%E2%80%9C%E9%87%8D%E8%BD%BD%E2%80%9D%E6%98%AF%E4%B8%AA%E5%95%A5%EF%BC%9F.php
參考檔案:
https://www.php.net/manual/zh/language.oop5.overloading.php#77843
===============
關注公眾號:【硬核專案經理】獲取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免費得PHP、專案管理學習資料
知乎、公眾號、抖音、頭條搜索【硬核專案經理】
B站ID:482780532
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/261969.html
標籤:PHP
