在物件導向程式設計中,「綁定」指的是函式呼叫與函式主體、成員存取與變數記憶體位址之間的關聯。簡單來說,就是決定當你呼叫一個方法或存取一個屬性時,到底會執行哪個類別的程式碼、讀取哪個記憶體位置的資料。
靜態綁定發生在編譯期,根據程式碼結構在執行前就確定關聯。它不依賴任何執行期資訊,適用於函式呼叫與函式主體、變數與記憶體區塊的固定對應。PHP 作為動態語言,本身不使用靜態綁定,但可以透過特定機制模擬。
動態綁定發生在執行期,根據物件的實際類型決定呼叫哪個方法或存取哪個屬性。這是多型的核心機制:當子類別覆寫父類別的方法或屬性時,透過父類別參考呼叫子類別實例的方法,會執行子類別的版本。
PHP 的 public 和 protected 成員預設使用動態綁定。例如:
<?php
class Father {
protected $salutation = "Hello there!";
public function getSalutation() {
print("$this->salutation ");
$this->identify();
}
protected function identify() {
print("I am Father. ");
}
}
class Son extends Father {
protected $salutation = "Hey!";
protected function identify() {
print("I am Son. ");
}
}
$obj = new Son();
$obj->getSalutation(); // 輸出:Hey! I am Son.
?>
雖然 getSalutation() 定義在 Father 中,但因為 $obj 是 Son 實例,動態綁定使其存取 Son 覆寫的 $salutation 和 identify()。
private 成員僅存在於定義它們的類別內部,不會被繼承。PHP 對 private 成員採用模擬靜態綁定:在父類別方法中存取 $this->privateMember 時,永遠綁定父類別的版本,即使子類別定義了同名屬性。
<?php
class Father {
private $salutation = "Hello there!";
public function getSalutation() {
print("$this->salutation ");
$this->identify();
}
private function identify() {
print("I am Father. ");
}
}
class Son extends Father {
private $salutation = "Hey!";
private function identify() {
print("I am Son. ");
}
}
$obj = new Son();
$obj->getSalutation(); // 輸出:Hello there! I am Father.
?>
動態綁定允許子類別在不修改父類別介面的前提下改變行為。經典範例是權限控制:
<?php
class User {
protected function isAuthorized() { return false; }
public function deleteUser($username) {
if (!$this->isAuthorized()) {
print("You are not authorized. ");
return false;
}
print("User deleted. ");
}
}
class AuthorizedUser extends User {
protected function isAuthorized() { return true; }
}
$user = new User();
$admin = new AuthorizedUser();
$user->deleteUser("Zeev"); // 輸出:You are not authorized.
$admin->deleteUser("Zeev"); // 輸出:User deleted.
?>
deleteUser() 呼叫 $this->isAuthorized(),動態綁定根據實際物件類型決定呼叫哪個版本,實現了開放封閉原則。
private 成員用於明確禁止子類別覆寫特定實作細節,確保核心邏輯不被意外改變。良好的物件層次應允許大多數功能可被特化,僅在確定不希望子類別介入時使用 private。