## 抽象類
php5支持抽象類和抽象方法。類前加 abstract, 此類就成為抽象類,**無法被實例化**,此類天生就是用來被繼承的,給子類提供了一個類的模板;
類方法前加 abstract,是抽象方法,**抽象方法不能有方法體;**
總結下來抽象類有以下幾個特點:
1. 類中有抽象方法,則此類一定要是抽象類;否則會報錯;
2. 抽象類中的方法不一定都是抽象方法;
3. 決定類是否能被實例化取決于其是不是抽象類,就算其類中的方法全部都是具體的方法而類本身是抽象方法的話,也不能被實例化
4. 抽象類中全是具體方法,但是抽象類又不能被實例化,又想用其里面的具體方法時,就可以通過繼承的方式或者通過類來調用;
5. 抽象類是用作被繼承的類,所以其中的方法必須是public或者protected,又由于子類繼承其父類不能令其權限越來越嚴格的規則,其子類也必須public或者protected;
6. 如果是一個非抽象類繼承抽象類,就必須要完成抽象類中的所有的所有抽象方法(并且參數及其參數的類型要一樣),但如果是一個抽象類繼承一個抽象類的話可以不必完成抽象類中的抽象方法(抽象類繼承抽象類的目的就是擴展被繼承的抽象類);
*以下代碼摘抄自燕十八公益課堂*
```php
/*
春秋戰國時期,燕零七 飛行器專家,能工巧匠.
他寫了一份圖紙---飛行器制造術
飛行器秘制圖譜
1: 要有一個有力的發動機,噴氣式.
2: 要有一個平衡舵,掌握平衡
他的孫子問: 發動機怎么造呢?
燕零七眼望夕陽: 我是造不出來,但我相信后代有人造出來
燕零七的構想在當時的科技造不出來,即這個類只能在圖紙化,無法實例化.
***/
// 此時這個類沒有具體的方法去實現,還太抽象.
// 因此我們把他做成一個抽象類
abstract class FlyIdea {
// 大力引擎,當時也沒法做,這個方法也實現不了,因此方法也是抽象的
public abstract function engine();
// 平衡舵
public abstract function blance();
/*
注意:抽象方法 不能有方法體
下面這樣寫是錯誤的
public abstract function blance() {
}
Fatal error: Abstract function FlyIdea::engine() cannot contain body
*/
}
/*
抽象類不能 new 來實例化
下面這行是錯誤的
$kongke = new FlyIdea();
Cannot instantiate abstract class FlyIdea
*/
// 到了明朝,萬戶用火箭解決了發動機的問題
abstract class Rocket extends FlyIdea {
// 萬戶把engine方法,給實現了,不再抽象了
public function engine() {
echo '點燃火藥,失去平衡,嘭!<br />';
}
// 但是萬戶實現不了平衡舵,因此平衡舵對于Rocket類來說,還是抽象的,類也是抽象的
// 此處由于繼承父類的也是抽象類,所以可以不必完成抽象類中的所有抽象方法;
}
/*
到了現代,燕十八親自制作飛行器
這個Fly類中,所以抽象方法,都已經實現了,不再是夢想.
*/
//到了這個類就必須要完成所有的抽象方法;
class Fly extends Rocket{
public function engine() {
echo '有力一扔<br />';
}
public function blance() {
echo '兩個紙翼保持平衡~~~';
}
public function start() {
$this->engine();
for($i=0;$i<10;$i++) {
$this->blance();
echo '平穩飛行<br />';
}
}
}
$apache = new Fly();
$apache->start();
```
## 接口
接口是 PHP對象之間的契約,抽象方法和靜態常量定義的集合。接口是一種特殊的抽象類,這種抽象類中只包含抽象方法和靜態常量。接口中沒有其它類型的內容。
總結如下:
1. 接口是某類事物功能的抽象,本身方法默認全部是抽象的,不能有方法體;
2. 接口的作用:指定了implements這些接口的類必須要包含接口里面的方法以及方法里面的參數,缺一不可。當然除了包含接口的這些方法外,可以增加其他的一些方法;
3. 接口是可以繼承的
4. 接口是一堆方法的說明,不能加屬性,但可以定義常量,定義的常量是不能被覆蓋,訪問方法是 **接口名::常量名** 或者 **self::常量名**
5. 接口的方法必須是public;
6. 類可以實現多接口
*以下代碼來自燕十八的公益課堂*
```php
<?php
header("Content-type: text/html; charset=utf-8");
/*
類: 是某一類事物的抽象,是某類對象的藍圖.
比如: 女媧造人時,腦子中關于人的形象 就是人類 class Human
如果,女媧決定造人時, 同時,形象又沒最終定稿時,
她腦子有哪些支離破碎的形象呢?
她可能會這么思考:
動物: 吃飯
猴子: 奔跑
猴子: 哭
自己: 思考
小鳥: 飛
我造一種生物,命名為人,應該有如下功能
eat()
run();
cry();
think();
類如果是一種事物/動物的抽象
那么 接口,則是事物/動物的功能的抽象,
即,再把他們的功能各拆成小塊
自由組合成新的特種
*/ ;
interface animal {
const NAME = 'zxg'; //不能定義屬性,但可以定義常量;
public function eat();
}
interface monkey {
public function run();
public function cry();
}
interface wisdom {
public function think();
}
interface bird {
public function fly();
}
/*
如上,我們把每個類中的這種實現的功能拆出來
分析: 如果有一種新生物,實現了eat() + run() +cry() + think() ,這種智慧生物,可以叫做人.
class Human implements animal,monkey,wisdom {
}
Human類必須要包含animal,monkey,wisdom接口里面的方法,缺一不可,否則就會報錯
Class Human contains 4 abstract methods
*/
class Human implements animal, monkey, wisdom, bird { //這里的接口數量可以隨意增加;增加了以后本類里面的方法必須要有新增加的接口里面的方法
public function eat() {
echo "吃東西方法";
}
public function run() {
echo self::NAME; //可以通過self來訪問任意一個接口所定義的常量;
echo '行走的方法';
}
public function cry() {
echo '哭的方法';
}
public function think() {
echo animal::NAME; //也可以通過 接口名
echo '思考的方法';
}
public function smile() {
echo "這是新增加的微笑方法";
}
public function fly() {
echo "這是新增加的接口bird里面的fly方法";
}
}
$obj = new Human();
$obj -> think();
?>
```
## 區別
1. 對接口的使用是通過關鍵字implements。對抽象類的使用是通過關鍵字extends。當然接口也可以通過關鍵字extends繼承但最好還是通過implements實現。
2. 接口中不可以聲明成員變量(包括類靜態變量),但是可以聲明類常量。抽象類中可以聲明各種類型成員變量,實現數據的封裝。
3. 接口中只有抽象方法沒有具體的方法,抽象類可以有具體的方法。
4. 接口中的方法默認都是public類型的,而抽象類中的方法可以使用protected,public來修飾(其實抽象類也可以聲明private方法的,不過沒有意義)。
5. 一個類可以同時實現多個接口,但一個類只能繼承于一個抽象類。
### 使用接口還是抽象類?
1. 如果要創建一個模型,這個模型將由一些緊密相關的對象采用,就可以使用抽象類。如果要創建將由一些不相關對象采用的功能,就使用接口。
2. 如果必須從多個來源繼承行為,就使用接口(只有接口能繼承多個)。
3. 如果知道所有類都會共享一個公共的行為實現,就使用抽象類,并在其中實現該行為。
## 應用場景舉例
> 更多的應用場景可以參考一些國外框架,比如YII
```php
<?php
//04.php
/***
====筆記部分====
面向對象的一個觀點:
做的越多,越容易犯錯
抽象類{就定義類模板}--具體子類實現{china,japan,english}
接口:
***/
// 抽象的數據庫類
/*
創業做網站
到底用什么數據庫? mysql, oracle,sqlserver,postgresql?
這樣:先開發網站,運行再說.
先弄個mysql開發著,正式上線了再換數據庫也不遲
引來問題:
換數據庫,會不會以前的代碼又得重寫?
答:不必,用抽象類
開發者,開發時,就以db抽象類來開發.
*/
abstract class db {
public abstract function connect($h,$u,$p);
public abstract function query($sql);
public abstract function close();
}
/*
// 下面這個代碼有誤
// 因為子類實現時, connect和抽象類的connect參數不一致
class mysql extends db {
public function connect($h,$h) {
return true;
}
public function query($sql,$conn) {
}
public function close() {
}
}
*/
/*
下面這個mysql類,嚴格實現了db抽象類
試想: 不管上線時,真正用什么數據庫
我只需要再寫一份如下類
class oracle extends db {
}
class mssql extends db {
}
class postsql extends db {
}
業務邏輯層不用改?
為什么不用改?
因為都實現的db抽象類.
我開發時,調用方法不清楚的地方,我就可以參考db抽象類.
反正子類都是嚴格實現的抽象類.
*/
class mysql extends db {
public function connect($h,$h,$u) {
return true;
}
public function query($sql) {
}
public function close() {
}
}
/*
接口 就更加抽象了
比如一個社交網站,
關于用戶的處理是核心應用.
登陸
退出
寫信
看信
招呼
更換心情
吃飯
罵人
搗亂
示愛
撩騷
這么多的方法,都是用戶的方法,
自然可以寫一個user類,全包裝起來
但是,分析用戶一次性使不了這么方法
用戶信息類:{登陸,寫信,看信,招呼,更換心情,退出}
用戶娛樂類:{登陸,罵人,搗亂,示愛,撩騷,退出}
開發網站前,分析出來這么多方法,
但是,不能都裝在一個類里,
分成了2個類,甚至更多.
作用應用邏輯的開發,這么多的類,這么多的方法,都暈了.
*/
interface UserBase {
public function login($u,$p);
public function logout();
}
interface UserMsg {
public function wirteMsg($to,$title,$content);
public function readMsg($from,$title);
}
interface UserFun {
public function spit($to);
public function showLove($to);
}
/*
作為調用者, 我不需要了解你的用戶信息類,用戶娛樂類,
我就可以知道如何調用這兩個類
因為: 這兩個類 都要實現 上述接口.
通過這個接口,就可以規范開發.
*/
/*
下面這個類,和接口聲明的參數不一樣,就報錯,
這樣,接口強制統一了類的功能
不管你有幾個類,一個類中有幾個方法
我只知道,方法都是實現的接口的方法.
*/
class User implements UserBase {
public function login($u) {
}
}
?>
```
- 現代化PHP特性
- php7常用特性整理
- 反射機制Reflection
- 依賴注入與服務容器
- 抽象類與接口
- 類多繼承的替代方案Traits
- 類的延遲綁定(后期綁定)
- 生成器語法
- 匿名函數和閉包
- 匿名類
- 理解php的output buffer
- 斷言ASSERT
- 魔術方法小結
- Zend Opcache字節碼緩存
- 內置的http服務器
- SPL標準庫
- 【SPL標準庫專題(1)】SPL簡介
- 【SPL標準庫專題(2)】Iterator
- 【SPL標準庫專題(3)】Classes
- 【SPL標準庫專題(4)】Exceptions
- 【SPL標準庫專題(5)】Datastructures:SplDoublyLinkedList
- 【SPL標準庫專題(6)】Datastructures:SplStack & SplQueue
- 【SPL標準庫專題(7)】Datastructures:SplPriorityQueue
- 【SPL標準庫專題(8)】Datastructures:SplHeap & SplMaxHeap & SplMinHeap
- 【SPL標準庫專題(9)】Datastructures:SplFixedArray
- 【SPL標準庫專題(10)】Datastructures:SplObjectStorage
- PHPcomposer使用手札[ing]
- PHP中的多態
- 通過命名空間實現自動加載的框架雛形
- 日期與金額
- PHPstorm使用攻略
- 筆記本