在 PHP 物件導向程式設計中,$this、static、final、const、self 是五個核心關鍵字,分別控制實例存取、靜態成員、繼承限制、常數定義與類別自我引用。掌握它們的差異與適用場景,是寫出健壯、可維護 PHP 程式碼的關鍵。本文將逐一深度解析並提供實戰範例。
$this 是在類別內部方法中,指向「當前實例化物件」的特殊變數。只能在非靜態方法中使用。
$this->propertyName; $this->methodName();
class User {
private string $name;
private int $loginCount = 0;
public function __construct(string $name) {
$this->name = $name; // 設定實例屬性
}
public function greet(): string {
return "Hello, {$this->name}!"; // 讀取實例屬性
}
public function login(): void {
$this->loginCount++; // 修改實例屬性
$this->logLogin(); // 呼叫實例方法
}
private function logLogin(): void {
error_log("User {$this->name} logged in. Count: {$this->loginCount}");
}
}
$user1 = new User('Alice');
$user2 = new User('Bob');
echo $user1->greet(); // Hello, Alice!
$user1->login();
$user1->login();
echo $user1->greet(); // 仍為 Hello, Alice! (loginCount 內部變化)
$user1 與 $user2 的 $name、$loginCount 互不干擾self::$staticProp 或 ClassName::$staticPropclass Counter {
public static int $count = 0; // 靜態屬性
public static function increment(): void {
self::$count++; // 類內部存取用 self::
}
public static function getCount(): int {
return self::$count;
}
}
Counter::increment();
Counter::increment();
echo Counter::getCount(); // 2
echo Counter::$count; // 2 (公開屬性可直接存取)
ClassName::staticMethod()static:: vs self::class ParentClass {
public static function whoAmI() {
echo __CLASS__ . "\n";
}
public static function testSelf() {
self::whoAmI(); // 編譯期綁定:永遠是 ParentClass
}
public static function testStatic() {
static::whoAmI(); // 執行期綁定:依實際呼叫類別決定
}
}
class ChildClass extends ParentClass {
public static function whoAmI() {
echo __CLASS__ . "\n";
}
}
ParentClass::testSelf(); // 輸出:ParentClass
ParentClass::testStatic(); // 輸出:ParentClass
ChildClass::testSelf(); // 輸出:ParentClass (self 綁定父類)
ChildClass::testStatic(); // 輸出:ChildClass (static 延遲綁定到子類)
function generateId(): int {
static $id = 0; // 僅初始化一次,跨呼叫保持值
return ++$id;
}
echo generateId(); // 1
echo generateId(); // 2
echo generateId(); // 3
final class:類別不可被繼承final function:方法不可被子類別覆寫final const:PHP 8.1+ 支援,常數不可被子類別覆寫final class SecurityService {
// 此類別不可被繼承
public function encrypt(string $data): string {
// 加密邏輯
}
}
// class HackerService extends SecurityService {} // Fatal Error: Cannot extend final class
class ApiController {
final public function handleRequest(): void {
// 核心流程不可被子類別修改
$this->validate();
$this->process();
$this->respond();
}
protected function validate(): void { /* ... */ }
protected function process(): void { /* ... */ }
protected function respond(): void { /* ... */ }
}
class CustomApiController extends ApiController {
// public function handleRequest() {} // Fatal Error: Cannot override final method
// 但可覆寫 protected 方法擴充行為
protected function process(): void {
parent::process();
$this->logCustomMetrics();
}
}
final,除非明確設計為可繼承(開放/封閉原則)final,擴充點提供 protected 方法供覆寫class Math {
public const PI = 3.14159265359;
protected const DEFAULT_PRECISION = 2;
private const INTERNAL_VERSION = '1.0.0';
}
| 位置 | 語法 | 範例 |
|---|---|---|
| 類別內部 | self::CONST_NAME | self::PI |
| 類別外部 (public) | ClassName::CONST_NAME | Math::PI |
| 子類別內部 | parent::CONST_NAME 或 self::CONST_NAME | parent::PI |
$ 符號:const PI = 3.14(非 const $PI)final const 防止覆寫class OrderStatus {
public const PENDING = 'pending';
public const PAID = 'paid';
public const SHIPPED = 'shipped';
public const COMPLETED = 'completed';
public const CANCELLED = 'cancelled';
public static function getValidTransitions(string $from): array {
return match($from) {
self::PENDING => [self::PAID, self::CANCELLED],
self::PAID => [self::SHIPPED, self::CANCELLED],
self::SHIPPED => [self::COMPLETED],
default => [],
};
}
}
// 使用
$status = OrderStatus::PAID;
$next = OrderStatus::getValidTransitions($status); // ['shipped', 'cancelled']
self 代表「當前類別」(編譯期綁定),用於存取靜態成員、常數、呼叫靜態方法。與 static(執行期綁定)形成對比。
self::CONSTself::$staticPropself::staticMethod()new self()(工廠模式常見)function setSelf(self $obj)(PHP 7.1+,限制為當前類別實例,不含子類)| 特性 | $this | self | static |
|---|---|---|---|
| 綁定時機 | 執行期 (實例) | 編譯期 (類別) | 執行期 (類別) |
| 存取實例成員 | ✅ | ❌ | ❌ |
| 存取靜態成員 | ❌ | ✅ | ✅ (LSB) |
| 存取常數 | ❌ | ✅ | ✅ |
| 繼承行為 | 指向實際實例類別 | 永遠指向定義類別 | 指向實際呼叫類別 |
| 可用於型別提示 | ❌ | ✅ (PHP 7.1+) | ❌ |
abstract class Product {
abstract public function getName(): string;
// 靜態工廠方法
public static function create(string $type): self {
return match($type) {
'book' => new Book(),
'phone' => new Phone(),
default => throw new InvalidArgumentException("Unknown type: $type"),
};
}
}
class Book extends Product {
public function getName(): string { return 'Book'; }
}
class Phone extends Product {
public function getName(): string { return 'Phone'; }
}
// 使用
$product = Product::create('book'); // 回傳 Book 實例,型別為 Product
echo $product->getName(); // Book
final class Database {
// 1. const: 配置常數
private const DEFAULT_DSN = 'mysql:host=localhost;dbname=app';
private const DEFAULT_USER = 'root';
private const DEFAULT_PASS = '';
// 2. static: 單例儲存
private static ?self $instance = null;
// 3. 實例屬性
private PDO $pdo;
// 4. 私有建構子防止外部 new
private function __construct() {
$this->pdo = new PDO(
self::DEFAULT_DSN,
self::DEFAULT_USER,
self::DEFAULT_PASS,
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
}
// 5. 靜態工廠方法 (使用 self 型別提示)
public static function getInstance(): self {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
// 6. 禁止克隆與反序列化
private function __clone() {}
public function __wakeup() {
throw new Exception("Cannot unserialize singleton");
}
// 7. 代理 PDO 方法
public function query(string $sql): PDOStatement {
return $this->pdo->query($sql);
}
// 8. final 方法防止覆寫核心邏輯
final public function beginTransaction(): bool {
return $this->pdo->beginTransaction();
}
}
// 使用
$db = Database::getInstance();
$stmt = $db->query('SELECT * FROM users');
$thisself::$prop 或 static::$propconst $PI = 3.14$,寫 const PI = 3.14final 方法finalself:: 調用被子類別覆寫的靜態方法static:: 實現延遲靜態綁定self 作為型別提示static 回傳型別final const、readonly 屬性(可替代部分常數用途)readonly 類別