1、繼承單接口方式
interface testA{
function echostr();
}
interface testB extends testA{
function dancing($name);
}
class testC implements testB{
function echostr(){
echo "接口繼承,要實(shí)現(xiàn)所有相關(guān)抽象方法!";
echo "<br>";
}
function dancing($name){
echo $name."正在跳舞!";
}
}
$demo=new testC();
$demo->echostr();
$demo->dancing("模特");
//運(yùn)行結(jié)果
/**
接口繼承,要實(shí)現(xiàn)所有相關(guān)抽象方法
模特正在跳舞!
**/
//還有另外一個(gè)例子
interface UserInterface{ //定義User的接口
function getname();
}
interface TeacherInterface{ //teacher相關(guān)接口
function getLengthOfService();
}
class User implements UserInterface { //實(shí)現(xiàn)UserInterface接口
private $name = "tom";
public function getName(){
return $this->name;
}
}
class Teacher implements TeacherInterface { //實(shí)現(xiàn)TeacherInterface接口
private $lengthOfService = 5; // 工齡
public function getLengthOfService(){
return $this->lengthOfService;
}
}
// 繼承自User類,同時(shí)實(shí)現(xiàn)了TeacherInterface接口.
class GraduateStudent extends User implements TeacherInterface {
private $teacher ;
public function __construct(){
$this->teacher = new Teacher();
}
public function getLengthOfService(){
return $this->teacher->getLengthOfService();
}
}
class Act{
//注意這里的類型提示改成了接口類型
public static function getUserName(UserInterface $_user){
echo "Name is " . $_user->getName() ."<br>";
}
//這里的類型提示改成了TeacherInterface類型.
public static function getLengthOfService(TeacherInterface $_teacher){
echo "Age is " .$_teacher->getLengthOfService() ."<br>";
}
}
$graduateStudent = new GraduateStudent();
Act::getUserName($graduateStudent);
Act::getLengthOfService($graduateStudent);
//結(jié)果正如我們所要的,實(shí)現(xiàn)了有多重身份的一個(gè)對(duì)象.
2、繼承多接口方式
interface testA{
function echostr();
}
interface testB{
function dancing($name);
}
interface testC extends testA,testB{
function singing($nickname);
}
class testD implements testC{
function echostr(){
echo "接口繼承,要實(shí)現(xiàn)父接口所有相關(guān)方法!";
echo "<br />";
}
function dancing($name){
echo $name."正在跳舞!";
echo "<br />";
}
function singing($nickname){
echo $nickname."正在唱歌!";
}
}
$demo=new testD();
$demo->echostr();
$demo->dancing("模特");
$demo->singing("周杰倫");
//運(yùn)行結(jié)果
/**
接口繼承,要實(shí)現(xiàn)父接口所有相關(guān)方法!
模特正在跳舞!
周杰倫正在唱歌!
**/
需要注意的是當(dāng)你接口繼承其它接口時(shí)候,直接繼承父接口的靜態(tài)常量屬性和抽象方法,所以類實(shí)現(xiàn)接口時(shí)必須實(shí)現(xiàn)所有相關(guān)的抽象方法
3、使用trait
- 自php5.4.0起,php實(shí)現(xiàn)了一種代碼復(fù)用的方法稱為trait.
- Trait是為類似php的單繼承語言所準(zhǔn)備的一種代碼服用機(jī)制。Trait為了減少單繼承語言的限制,使開發(fā)人員能夠自由地在不同層次結(jié)構(gòu)內(nèi)獨(dú)立的類復(fù)用method. Trait 和Class 組合的語義定義了一種減少復(fù)雜性的方式,避免傳統(tǒng)的多繼承和 Mixin 類相關(guān)典型問題。
- Trait 和 Class 相似,但僅僅旨在用細(xì)粒度和一致的方式來組合功能。 無法通過 trait 自身來實(shí)例化。它為傳統(tǒng)繼承增加了水平特性的組合;也就是說,應(yīng)用的幾個(gè) Class 之間不需要繼承。
- 優(yōu)先級(jí):從基類繼承的成員被 trait 插入的成員所覆蓋。優(yōu)先順序是來自當(dāng)前類的成員覆蓋了 trait 的方法,而 trait 則覆蓋了被繼承的方法。
class Base {
public function sayHello() {
echo 'Hello ';
}
}
trait SayWorld {
public function sayHello() {
parent::sayHello();
echo 'World!';
}
}
class MyHelloWorld extends Base {
use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
//通過逗號(hào)分隔,在 use 聲明列出多個(gè) trait,可以都插入到一個(gè)類中。
4、通過組合模擬多重繼承
class User {
private $name = "tom";
public function getName(){
return $this->name;
}
}
class Teacher{
private $lengthOfService = 5; // 工齡
public function getLengthOfService(){
return $this->lengthOfService;
}
}
// 上面的類中的set方法就不寫了.
// 如果有個(gè)研究生,既是學(xué)生也算工齡.
class GraduateStudent extends User {
private $teacher ;
public function __construct(){
$this->teacher = new Teacher();
}
public function getLengthOfService(){
return $this->teacher->getLengthOfService();
}
}
$graduateStudent = new GraduateStudent();
echo "name is ".$graduateStudent->getName()."<br>";
echo "lengthOfService is ".$graduateStudent->getLengthOfService();
5、利用__call & 回調(diào)函數(shù)實(shí)現(xiàn)
其中使用的兩個(gè)函數(shù)可以關(guān)注下,然后別忘了,恢復(fù)__call默認(rèn)行為
is_callable
call_user_func_array
class Parent1 {
function method1() {}
function method2() {}
}
class Parent2 {
function method3() {}
function method4() {}
}
class Child {
protected $_parents = array();
public function Child(array $parents=array()) {
$this->_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);
}
}
// 恢復(fù)默認(rèn)的行為,會(huì)引發(fā)一個(gè)方法不存在的致命錯(cuò)誤
return call_user_func_array(array($this, $method), $args);
}
}
$obj = new Child(array(new Parent1(), new Parent2()));
print_r( array($obj) );die;
$obj->method1();
$obj->method3();
補(bǔ)充內(nèi)容 - 接口
接口是什么?
使用接口(interface),可以指定某個(gè)類必須實(shí)現(xiàn)哪些方法,但不需要定義這些方法的具體內(nèi)容。
接口是通過 interface 關(guān)鍵字來定義的,就像定義一個(gè)標(biāo)準(zhǔn)的類一樣,但其中定義所有的方法都是空的。
接口中定義的所有方法都必須是公有,這是接口的特性。什么時(shí)候用接口?
1、定規(guī)范,保持統(tǒng)一性;
2、多個(gè)平級(jí)的類需要去實(shí)現(xiàn)同樣的方法,只是實(shí)現(xiàn)方式不一樣-
接口使用規(guī)范
- 接口不能實(shí)例化
- 接口的屬性必須是常量
- 接口的方法必須是public【默認(rèn)public】,且不能有函數(shù)體
- 類必須實(shí)現(xiàn)接口的所有方法
- 一個(gè)類可以同時(shí)實(shí)現(xiàn)多個(gè)接口,用逗號(hào)隔開
- 接口可以繼承接口【用的少】
思考問題:
所以,我們到底為什么要使用多繼承?
emmm,這是個(gè)好問題,因?yàn)槲覜]有答案,當(dāng)然可能是我還沒有遇到過必須使用多繼承的場(chǎng)景。
不過就目前見識(shí)來看,接口,抽象類已經(jīng)很足夠使用了,所以私以為,可能多繼承主要應(yīng)用場(chǎng)景是一些遺留問題吧?歡迎看官指正了。