學(xué)習(xí)要點(diǎn):
OOP 的封裝
OOP 的繼承
OOP 的多態(tài)
講師:楊應(yīng)勇
面向?qū)ο蟮娜齻€(gè)主要特性是封裝、繼承和多態(tài)。
一、OOP的封裝
隱藏對(duì)象的字段和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外公開接口,控制在程序中字段的讀和修改的訪問級(jí) 別;將抽象得到的數(shù)據(jù)和行為(或功能)相結(jié)合,形成 一個(gè)有機(jī)的整體,也就是將數(shù)據(jù)與 操作數(shù)據(jù)的源代碼進(jìn)行有機(jī)的結(jié)合,形成“類”,其中數(shù)據(jù)和函數(shù)都是類的成員。
字段的作用域
1.public 公共的 (類外可以訪問)
2.private 私有的 (類內(nèi)可以訪問)
3.protected 受保護(hù)的 (類內(nèi)和子類可以訪問,類外不可訪問)
創(chuàng)建使用了私有的字段,這樣外部就無(wú)法訪問了
class Computer {
//類的字段(成員)
private $name = '聯(lián)想小星';
private $model = 'LX';
}
通過(guò)一個(gè)公共方法作為入口,訪問私有字段,而必須使用$this關(guān)鍵字。
class Computer {
//類的字段(成員)
private $name = '聯(lián)想小星';
private $model = 'LX';
//通過(guò)公共方法來(lái)訪問私有字段
function run () {
echo $this->name;
}
}
$computer->run();
屬性操作(私有字段的賦值與取值)
可以設(shè)計(jì)兩個(gè)公共方法,一個(gè)方法為setName(),用于賦值;一個(gè)方法為getName(), 用于取值。
class Computer {
//類的字段(成員) private $name;
private $model;
//賦值
function setName($name) {
$this->name = $name;
}
//取值
function getName() {
return $this->name;
}
}
$computer = new Computer();
$computer->setName('IBM');
echo $computer->getName();
如果有十個(gè)字段那么就必須要二十個(gè)方法才能夠賦值和取值,那么有沒有更簡(jiǎn)便的方法 呢?PHP內(nèi)置兩個(gè)方法(攔截器)專門用于取值與賦值: set(), get()。
class Computer {
//類的字段(成員)
private $name;
private $model;
//所有字段的賦值都在這里進(jìn)行
function set($_key,$_value) {
$this->$_key = $_value;
}
//所有字段的取值都在這里進(jìn)行
function get($_key) {
return $this->$_key;
}
}
$computer = new Computer();
$computer->model = 'LX';
echo $computer->model;
方法私有:有些使用類里面的方法并不需要對(duì)外公開,只是里面運(yùn)作的一部分,這個(gè)時(shí) 候可以將方法也封裝起來(lái)。
class Computer {
//類的字段(成員)
private $name;
private $model;
//私有方法
private function getEcho() {
echo '我是私有化的方法';
}
//公共方法一般是對(duì)外的入口
public function run() {
$this->getEcho();
}
}
$computer = new Computer();
$computer->run();
建議:方法前面如果沒有修飾符,那么就是外部可訪問的公共方法,但為了讓程序更加 的清晰,建議在前面加上public。
常量(constant) 在類中可以定義常量,用來(lái)表示不會(huì)改變的值。對(duì)于從該類實(shí)例化的任何對(duì)象來(lái)說(shuō),常
量值在這些對(duì)象的整個(gè)生命周期中都保持不變。
class Computer {
const PI = 3.1415926;
}
echo Computer::PI;
靜態(tài)類成員
有時(shí)候,可能需要?jiǎng)?chuàng)建供所有類實(shí)例共享的字段和方法,這些字段和方法與所有的類實(shí) 例有關(guān),但不能由任何特定對(duì)象調(diào)用。
class Computer {
public static $_count = 0;
}
echo Computer::$_count;
一般來(lái)說(shuō),必須將字段做成私有化。所以可能需要這么做:
class Computer {
private static $_count = 0;
public static function setRun() {
self::$_count++;
}
public static function getRun() {
return self::$_count;
}
}
Computer::setRun();
echo Computer::getRun();
Instanceof關(guān)鍵字
PHP5有一個(gè)instanceof關(guān)鍵字,使用這個(gè)關(guān)鍵字可以確定一個(gè)對(duì)象是類的實(shí)例、類的 子類,還是實(shí)現(xiàn)了某個(gè)特定接口,并進(jìn)行相應(yīng)的操作。
class Computer {
//
}
$computer = new Computer();
echo ($computer instanceof Computer);
二、OOP繼承
繼承是從一個(gè)基類得到一個(gè)或多個(gè)類的機(jī)制。 繼承自另一個(gè)類的類被稱為該類的子類。這種關(guān)系通常用父類和孩子來(lái)比喻。子類將繼
承父類的特性。這些特性由屬性和方法組成。子類可以增加父類之外的新功能,因此子類也 被稱為父類的“擴(kuò)展”。
在PHP中,類繼承通過(guò)extends關(guān)鍵字實(shí)現(xiàn)。繼承自其他類的類成為子類或派生類,子 類所繼承的類成為父類或基類。(PHP只支持單繼承,PHP不支持方法重載)。
class Computer {
private $name = '聯(lián)想小星';
private function get($_key) {
return $this->$_key;
}
public function run() {
echo '我是父類';
}
}
class NoteBookComputer extends Computer {
}
$notebookcomputer = new NoteBookComputer();
$notebookcomputer->run();
echo $notebookcomputer->name;
字段和方法的重寫(覆蓋) 有些時(shí)候,并不是特別需要父類的字段和方法,那么可以通過(guò)子類的重寫來(lái)修改父類的
字段和方法。
class Computer {
public $name = '聯(lián)想小星'; protected function run() {
echo '我是父類';
}
}
class NoteBookComputer extends Computer {
public $name = 'IBM';
public function run() { echo '我是子類';
}
}
子類調(diào)用父類的字段或方法 為了安全,我們一般將父類的方法封裝了起來(lái),這樣,外部就無(wú)法調(diào)用,只能被繼承它
的子類所看到。這個(gè)時(shí)候,就需要通過(guò)子類操作來(lái)調(diào)用父類了。
class Computer {
protected $name = '聯(lián)想小星';
protected function run() {
echo '我是父類';
}
}
class NoteBookComputer extends Computer {
public function getName() {
echo $this->name;
}
public function getRun() {
echo $this->run();
}
}
通過(guò)重寫調(diào)用父類的方法 有的時(shí)候,我們需要通過(guò)重寫的方法里能夠調(diào)用父類的方法內(nèi)容,這個(gè)時(shí)候就必須使用
語(yǔ)法:父類名::方法() 或者parent::方法()即可調(diào)用。
class Computer {
protected function run() {
echo '我是父類';
}
}
class NoteBookComputer extends Computer {
public function run() {
echo Computer::run(); //
}
}
final關(guān)鍵字可以防止類被繼承,有些時(shí)候只想做個(gè)獨(dú)立的類,不想被其他類繼承使用, 那么就必須使用這個(gè)關(guān)鍵字。建議只要是單獨(dú)的類,都加上這個(gè)關(guān)鍵字。
final class Computer {
//無(wú)法繼承的類
final public function run() {} //無(wú)法被繼承的方法
}
class NoteBookComputer extends Computer {
//會(huì)報(bào)錯(cuò)
}
抽象類和方法(abstract) 抽象方法很特殊,只在父類中聲明,但在子類中實(shí)現(xiàn)。只有聲明為abstract的類可以聲明抽象方法。
規(guī)則:
1.抽象類不能被實(shí)例化,只能被繼承。
2.抽象方法必須被子類方法重寫。
abstract class Computer {
abstract function run();
}
final class NotebookComputer extends Computer {
public function run() {
echo '我實(shí)現(xiàn)了';
}
}
接口(interface) 接口定義了實(shí)現(xiàn)某種服務(wù)的一般規(guī)范,聲明了所需的函數(shù)和常量,但不指定如何實(shí)現(xiàn)。
之所以不給出實(shí)現(xiàn)的細(xì)節(jié),是因?yàn)椴煌膶?shí)體可能需要用不同的方式來(lái)實(shí)現(xiàn)公共的方法定 義。關(guān)鍵是要建立必須實(shí)現(xiàn)的一組一般原則,只要滿足了這些原則才能說(shuō)實(shí)現(xiàn)了這個(gè)接口。
規(guī)則:
1.類全部為抽象方法(不需要聲明abstract) 2.接口抽象方法必須是public 3.成員(字段)必須是常量
interface Computer {
const NAME = '聯(lián)想小星';
public function run();
}
final class NotebookComputer implements Computer { public function run() {
echo '實(shí)現(xiàn)了接口的方法';
}
}
$notebookcomputer = new NoteBookComputer();
$notebookcomputer->run();
echo Computer::NAME;
子類可以實(shí)現(xiàn)多個(gè)接口
interface Computer {
const NAME = '聯(lián)想小星';
public function run();
}
interface Notebook {
public function book();
}
final class NotebookComputer implements Computer,Notebook { public function run() {
echo '實(shí)現(xiàn)了接口的方法';
}
public function book() {
echo '實(shí)現(xiàn)了接口的方法';
}
}
三、多態(tài)
多態(tài)是指 OOP 能夠根據(jù)使用類的上下文來(lái)重新定義或改變類的性質(zhì)或行為,或者說(shuō)接口的多種不同的實(shí)現(xiàn)方式即為多態(tài)。把不同的子類對(duì)象都當(dāng)作父類來(lái)看,可以屏蔽不同子類 對(duì)象之間的差異,寫出通用的代碼,做出通用的編程,以適應(yīng)需求的不斷變化。
interface Computer {
public function version();
public function work();
}
class NotebookComputer implements Computer {
public function version() {
echo '聯(lián)想小星';
}
public function work() {
echo '筆記本正在隨時(shí)攜帶運(yùn)行!';
}
}
class desktopComputer implements Computer {
public function version() {
echo 'IBM';
}
public function work() {
echo '臺(tái)式電腦正在工作站運(yùn)行!';
}
}
class Person {
public function run(Computer $type) {
$type->version();
$type->work();
}
}
$person = new Person();
$desktopcomputer = new desktopComputer();
$notebookcomputer = new NoteBookComputer();
$person->run($notebookcomputer);