1、PHP沒有多繼承的特性。即使是一門支持多繼承的編程語言,我們也很少會使用這個特性。在大多數人看來,多繼承不是一種好的設計方法。想要給某個類添加額外的特性,不一定要使用繼承。這里我提供一種模擬多繼承的方法以供參考。
PHP有一個魔術方法,叫做__call。當你調用一個不存在的方法時,這個方法會被自動調用。這時,我們就有機會將調用重定向到一個存在的方法。繼承多個父類的子類,尋找方法的過程一般是這樣的:
本身的方法 -> 父類1的方法 -> 父類2的方法...
模擬過程大致是這樣:將各個父類實例化,然后作為子類的屬性。這些父類提供一些公有的方法。當子類擁有某方法時,__call()函數不會被調用。這相當於“覆蓋”了父類的方法。當調用了不存在的方法時,通過__call()方法依次從父類中尋找可以調用的方法。雖然這不是完備的多繼承,但可以幫助我們解決問題。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<?php
class
Parent1 {
function
method1() {}
function
method2() {}
}
class
Parent2 {
function
method3() {}
function
method4() {}
}
class
Child {
protected
$_parents
=
array
();
public
function
Child(
array
$parents
=
array
()) {
$_parents
=
$parents
;
}
public
function
__call(
$method
,
$args
) {
// 從“父類"中查找方法
foreach
(
$this
->_parents
as
$p
) {
if
(
is_callable
(
array
(
$p
,
$method
))) {
return
call_user_func_array(
array
(
$p
,
$method
),
$args
);
}
}
// 恢復默認的行為,會引發一個方法不存在的致命錯誤
return
call_user_func_array(
array
(
$this
,
$method
),
$args
);
}
}
$obj
=
new
Child(
array
(
new
Parent1(),
new
Parent2()));
$obj
->method1();
$obj
->method3();
|
這里沒有涉及屬性的繼承,但實現起來並不困難。可以通過__set()和__get()魔術方法來模擬屬性的繼承。請你動手實踐。
2、php中的類只能繼承一個父類,如果要繼承多個類應采用接口
下面來看一個接口多繼承的示例,代碼如下:
- <?php
- interface father{
- function shuchu();
- }
- interface mother{
- function dayin($my);
- }
- interface fam extends father,mother{
- function cook($name);
- }
- class test implements fam{
- function dayin($my){
- echo "我的名字是:".$my;
- echo "<br>";
- }
- function shuchu(){
- echo "接口繼承,要實現兩個抽象方法";
- echo "<br>";
- }
- function cook($name){
- echo "平時經常做飯的人是:".$name;
- }
- }
- $t=new test();
- $t->shuchu();
- $t->dayin("小強");
- $t->cook("媽媽");
- ?>
示例運行結果:
接口繼承,要實現兩個抽象方法 我的名字是:小強 平時經常做飯的人是:媽媽 |
這段代碼由於接口繼承了兩個接口,所有實例時要把這三個抽象類的所有抽象方法都實例,總共有三個。看完這兩個例子,你應該對接口的繼承熟悉了吧,其實就一個單繼承和多繼承,只要實現了所有相關的抽象方法就可以了。
3、php5.4以上可以用trait
<?php
trait ezcReflectionReturnInfo {
function getReturnType() { /*1*/ }
function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
use ezcReflectionReturnInfo;
/* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
use ezcReflectionReturnInfo;
/* ... */
}
?>