面向對象編程(OOP)引入了相當多的特性,使編程變得更加復雜.
封裝,繼承,多態是OOP的三要素,這些是過程式中的函數所沒有的.
具體體現在:
- 1.封裝: class/interface/public/protected/private
- 2.繼承: extends/implements
- 3.多態: 方法重寫/方法重載
新增的class和interface加入了新的變量作用域,即類和接口里代碼塊是函數所沒有的作用域.
在這個作用域里,可以定義變量和函數這些類和接口的成員,并且支持使用public/protected/private關鍵字對這些成員進行訪問控制.比如public表示允許外部訪問,protected表示允許類及其子類訪問,private表示只允許所在類內部訪問。
而且OOP還引入了方法重寫和方法重載這些多態特性,即:
- 方法重寫:參數列表相同,方法體不同.
- 方法重載:參數列表不同,方法體不同.
方法重寫依賴繼承,是子類的方法覆蓋父類的方法,要求方法名和參數列表相同.
方法重載不依賴繼承,是同一個類中的兩個或兩個以上的同名方法,參數列表不同。
需要注意的是繼承并重寫的方法只能維持或放大訪問權限,不能縮小.
比如父類protected方法在子類重載為public是可行的.
在PHP中,因為不允許存在多個同名方法,所以不支持C++/Java那樣的方法重載.
但PHP提供了魔術方法(__call,__callStatic)用于間接實現方法重載.
PHP中方法重寫并不要求參數相同.
PHP不支持多重繼承(繼承多個父類),但可以實現多個接口,也可以用trait特性間接支持多重繼承.
功能一覽
<?php
class A{//創建類A
//構造函數與析構函數
//構造函數 - 在創建對象時初始化對象, 即為對象成員變量賦初始值
function __construct() {
print "構造函數n<br />";
$this->name = "我是默認值<br />";
}
//析構函數 - 當對象結束其生命周期時(例如對象所在的函數已調用完畢),系統自動執行析構函數。
function __destruct() {
print "銷毀 " . $this->name . "n<br />";
}
//基礎元素
//創建屬性
public $a_a;
public $a_b='a_b';
//創建af方法
function af() {}
//創建常量
const constant = '常量值<br />';
function showConstant() {
echo self::constant . PHP_EOL;//打印常量,并加空格(代碼中)
}
//訪問權限
//公有的類成員可以在任何地方被訪問。
public $public = 'Public';
//受保護的類成員則可以被其自身以及其子類和父類訪問。
protected $protected = 'Protected';
//私有的類成員則只能被其定義所在的類訪問。
private $private = 'Private';
// 聲明一個公有的方法
public function MyPublic() { }
// 聲明一個受保護的方法
protected function MyProtected() { }
// 聲明一個私有的方法
private function MyPrivate() { }
//靜態
//創建一個公開的靜態方法
public static function aStaticMethod() {
// ...
echo "Hello<br />";
}
//創建公開的靜態屬性
public static $my_static = 'foo<br />';
public function staticValue() {
return self::$my_static;
}
}
class B extends A {//類B繼承類A
}
//實例化A類 - 可供使用的對象()
$class_a = 'A';
$a = new $class_a();
//B類的實例化 - 可供使用的對象
$b = new B;
//打印HelloHello
A::aStaticMethod();
$a::aStaticMethod();//上面已實例化過
?>
名詞解釋
class
- 每個類的定義都以關鍵字?
class
?開頭,后面跟著類名,后面跟著一對花括號,里面包含有類的屬性與方法的定義。 - 類名可以是任何非 PHP?保留字?的合法標簽。一個合法類名以字母或下劃線開頭,后面跟著若干字母,數字或下劃線。以正則表達式表示為:?
^[a-zA-Z_x80-xff][a-zA-Z0-9_x80-xff]*$
。 - 一個類可以包含有屬于自己的?常量,變量(稱為“屬性”)以及函數(稱為“方法”)。
- 當一個方法在類定義內部被調用時,有一個可用的偽變量?$this。$this?是一個到當前對象的引用。
new
要創建一個類的實例,必須使用?new
?關鍵字
屬性和方法
類的屬性和方法存在于不同的“命名空間”中,這意味著同一個類的屬性和方法可以使用同樣的名字。 在類中訪問屬性和調用方法使用同樣的操作符,具體是訪問一個屬性還是調用一個方法,取決于你的上下文,即用法是變量訪問還是函數調用。
extends
- 一個類可以在聲明中用?
extends
?關鍵字繼承另一個類的方法和屬性。PHP 不支持多重繼承,一個類只能繼承一個基類。 - 被繼承的方法和屬性可以通過用同樣的名字重新聲明被覆蓋。
::class
關鍵詞?class
?也可用于類名的解析。使用?ClassName::class
?可以獲取包含類?ClassName
?的完全限定名稱。
簽名兼容性規則
實例
轉一段王垠關于OOP的論述:
“對象思想”作為數據訪問的方式,是有一定好處的。 然而“面向對象”(多了“面向”兩個字),就是把這種本來良好的思想東拉西扯,牽強附會,發揮過了頭。 很多面向對象語言號稱“所有東西都是對象”,把所有函數都放進所謂對象里面,叫做“方法”,把普通的函數叫做“靜態方法”。 實際上只有極少需要抽象的時候,需要使用內嵌于對象之內,跟數據緊密結合的“方法”。 其他的時候,你其實只是想表達數據之間的變換操作,這些完全可以用普通的函數表達,而且這樣做更加簡單和直接。 把所有函數放進對象的做法是本末倒置的,因為函數本身并不屬于對象,它們只是對象上面的變換操作。 絕大部分函數是獨立于對象的,它們不能被叫做“方法”。 強制把所有函數放進它們本來不屬于的對象里面,把它們全都作為“方法”,導致了面向對象代碼邏輯過度復雜。 很簡單的想法,非得繞好多道彎子才能表達清楚。 很多人至今不知道自己所用的“面向對象語言”里面的很多優點,都是從過程式語言繼承來的。