可能我們日常工作中很少用到這塊知識點,但我還是喜歡把遇到的卻不清楚的知識點摸清
PHP的類方法重寫規則
1、final修飾的類方法不可被子類重寫
final修飾的類方法不可被子類重寫 即便final private方法無法被繼承 子類仍不能對齊進行重寫
1 class FinalMethod 2 { 3 //可繼承不可重寫 4 final public function finalPublic() 5 { 6 echo "can be inherited, but be overrided"; 7 } 8 //可繼承不可重寫 9 final protected function finalProtected() 10 { 11 echo "can be inherited, but be overrided"; 12 } 13 //不可繼承不可重寫 雖然子類繼承不到父類的private方法 但同時也會被final限制無法重寫 14 final private function finalPrivate() 15 { 16 echo "can not be inherited or be overrided"; 17 } 18 //雖然不可繼承 但子類里可重寫此方法 19 private function private() 20 { 21 echo "can not be inherited ,but be overrided"; 22 } 23 } 24 25 class Override extends FinalMethod 26 { 27 //error 28 public function finalPublic() 29 { 30 } 31 //error 32 protected function finalProtected() 33 { 34 } 35 //error 36 private function finalPrivate() 37 { 38 } 39 //correct 40 public/protected/private function private() 41 { 42 //子類繼承父類重寫父類方法時訪問級別只能更加寬松 不可更為嚴格 43 } 44 }
2、PHP是否重寫父類方法只會根據方法名是否一致判斷(5.3以后重寫父類方法參數個數必須一致)
這里並不是說方法參數無任何作用 PHP無重載機制 所以判斷是不是重寫只會通過方法名(C/C++不僅要方法名相同,參數也相同時才被視為重寫,否則即為重載,即新定義了一個多態函數的態) 當方法名相同時即被認為是在重寫父類方法,5.2可以參數不同,5.3以后參數需和父類方法一致,且都追尋繼承訪問級別的規則。
1 class Father 2 { 3 public function index($args_1) 4 { 5 } 6 } 7 8 class Child extends Father 9 { 10 //5.3以后重寫方法必須與父類保持參數個數相同 11 public function index($args_1, $args_2) 12 { 13 //在C/C++中此為重載非重寫,因為C/C++具有標准的多態機制,會因參數不同而視為某一方法的另一種態 14 //but在php中此依然為重寫 但5.3以后此為非法 必須與父類的方法參數個數保持一致 15 } 16 //5.3以后重寫方法必須與父類保持參數個數相同 17 private function index($args_1, $args_2) 18 { 19 //C/C++會因為參數不同於父類方法而視為重載,即新定義了一個函數的態,所以不會受到繼承訪問權限的限制 20 //但php仍然會被視為對父類方法的重寫,會受到繼承訪問權限的升降規則限制 21 } 22 }
3、重寫時訪問級別只可以等於或者寬松於父類 不可提升訪問級別
父類的public方法不能被子類重寫為protected或者private,protected方法不能被重寫為private,可以寬松er,不可以嚴格er
1 class Father 2 { 3 public function index() 4 { 5 } 6 } 7 8 class Child extends Father 9 { 10 protected/private function index() 11 { 12 //訪問權限提升 錯誤 13 //父類為public 則子類重寫也只能為public 14 //父類為protected 則子類可為public/protected 15 //父類為private 則子類public/protected/private皆可 16 } 17 }
其實關於訪問級別繼承規則有很多有趣的地方
private在我們常識中是無法被繼承的,子類拿不到,但其訪問級別已是最高,所以你在子類中可以寫成private protected public 仿佛是我們自己重新定義了一個函數一樣,這點在5.2版本之前尤其突出,因為5.2之前的版本在繼承重寫父類方法是可以不保持參數個數相同,但5.3以后加強了這方面的限制,參數個數必須與父類相同
注:
子類實現父類的抽象方法或某類實現接口的方法時其實仍屬於繼承關系,仍追尋訪問等級只能降低不可提升的規則
而且
抽象方法不可被聲明為private,abstract修飾的方法肯定是用於繼承實現的,所以只能是public或者protected 接口的方法聲明必須為public,interface里聲明的方法也肯定是被繼承實現的,且只能是public, implements 此接口的類也指定重寫成public類型的方法