類是物件導向程式設計 (OOP) 的核心藍圖,封裝屬性(狀態)與方法(行為)。PHP 5 起完整支援 OOP,提供 public/protected/private 可見性、static 靜態成員、final 禁止繼承/覆寫、魔術方法等豐富機制。本文系統整理類定義、成員聲明、存取控制、靜態特性、Final 關鍵字與所有魔術方法的用法與最佳實踐。
<?php
// 1.1 空類
class EmptyClass {}
// 1.2 含屬性與方法
class Person {
// 屬性聲明
public string $name = '匿名';
protected int $age = 0;
private string $idCard = '';
// 方法聲明
public function sayHello(): void {
echo "Hello, I'm {$this->name}.";
}
}
// 1.3 Final 類:禁止被繼承
final class FinalClass {
public function doSomething(): void {}
}
// 1.4 繼承 Final 類會報錯
// class Child extends FinalClass {} // Fatal error
?>
class 關鍵字定義。final class 禁止被繼承;final 也可修飾方法(禁止覆寫),但不能修飾屬性。<?php
class PropertyDemo {
// 2.1 可見性關鍵字
public $publicProp = '公有'; // 任何處可存取
protected $protectedProp = '受保護'; // 本類、子類、父類可存取
private $privateProp = '私有'; // 僅本類內部可存取
var $varProp = '舊式公有'; // PHP 5 視同 public,不建議使用
// 2.2 靜態屬性:屬於類而非實例,所有實例共享
public static int $instanceCount = 0;
private static string $secret = 'class-secret';
// 2.3 常量:不可變,隱含 public static
public const VERSION = '1.0.0';
protected const INTERNAL_ID = 123;
// 2.4 初始化規則:只能用常數表達式(PHP 8.1+ 支援 new Class())
public string $ok1 = 'constant';
public int $ok2 = 1 + 2; // 常數表達式
// public string $bad = $this->method(); // 錯誤:非編譯期常數
// public string $bad2 = someFunc(); // 錯誤:函數呼叫
}
?>
| 位置 | 非靜態屬性 | 靜態屬性 | 常量 |
|---|---|---|---|
| 類內部 (非靜態方法) | $this->prop | self::$prop / static::$prop | self::CONST |
| 類內部 (靜態方法) | 不可直接存取 | self::$prop / static::$prop | self::CONST |
| 類外部 | $obj->prop (需 public) | ClassName::$prop | ClassName::CONST |
| 子類內部 | $this->prop (protected/public) | parent::$prop / static::$prop | parent::CONST |
static::$prop 在繼承鏈中指向實際調用的類,而 self::$prop 永遠指向定義該屬性的類。建議靜態屬性存取優先使用 static::。
<?php
class MethodDemo {
public function publicMethod(): void {}
protected function protectedMethod(): void {}
private function privateMethod(): void {}
// 靜態方法:只能存取靜態成員
public static function staticMethod(): void {
echo self::$staticProp; // 正確
// echo $this->nonStatic; // 錯誤:靜態方法無 $this
}
// Final 方法:禁止子類覆寫
final public function finalMethod(): void {}
}
?>
final 方法不可覆寫,private 方法不可被子類看到,故子類可定義同名方法(實為新方法)。<?php
class LifeCycle {
public function __construct(string $name) {
$this->name = $name;
echo "建構: $name" . PHP_EOL;
}
public function __destruct() {
echo "解構: {$this->name}" . PHP_EOL;
}
// 複製物件時觸發
public function __clone() {
$this->id = uniqid(); // 重新生成唯一識別
}
}
$obj = new LifeCycle('A');
$obj2 = clone $obj; // 觸發 __clone
unset($obj); // 觸發 __destruct
?>
所有以 __ 開頭的方法均為魔術方法,必須宣告為 public。以下為常用魔術方法與觸發時機:
| 方法 | 觸發時機 | 典型用途 |
|---|---|---|
__construct(...$args) | 實例化 new Class() | 初始化屬性、注入依賴 |
__destruct() | 物件被銷毀 (unset、作用域結束、腳本結束) | 釋放資源、關閉連線、記錄日誌 |
__call($name, $args) | 呼叫不可見/不存在的實例方法 | 動態代理、方法欄位映射 |
__callStatic($name, $args) | 呼叫不可見/不存在的靜態方法 | 靜態工廠、動態查找 |
__get($name) | 讀取不可見/不存在的屬性 | 虛擬屬性、延遲載入 |
__set($name, $value) | 寫入不可見/不存在的屬性 | 資料驗證、自動轉型 |
__isset($name) | 對不可見/不存在屬性呼叫 isset()/empty() | 配合 __get 實作虛擬屬性存在性判斷 |
__unset($name) | 對不可見/不存在屬性呼叫 unset() | 清理虛擬屬性快取 |
__sleep() | serialize($obj) | 返回需序列化的屬性名陣列(排除資源、連線) |
__wakeup() | unserialize($data) | 重新建立資源連線、初始化狀態 |
__serialize() | serialize() (PHP 7.4+ 推薦) | 返回關聯陣列,完全控制序列化資料 |
__unserialize($data) | unserialize() (PHP 7.4+ 推薦) | 從關聯陣列還原狀態 |
__toString() | 物件被當作字串使用 (echo、print、字串拼接) | 返回物件的字串表示 |
__invoke(...$args) | 物件被當作函數呼叫 $obj() | 實作可呼叫物件、閉包替代 |
__set_state($props) | var_export($obj) (PHP 5.1+) | 返回重建物件的靜態方法,供 var_export 輸出可執行代碼 |
__debugInfo() | var_dump($obj) (PHP 5.6+) | 控制 var_dump 輸出的屬性(隱藏敏感資訊) |
<?php
class DynamicEntity {
private array $data = [];
private array $readonly = ['id', 'created_at'];
public function __get(string $name) {
return $this->data[$name] ?? null;
}
public function __set(string $name, $value) {
if (in_array($name, $this->readonly, true) && isset($this->data[$name])) {
throw new Exception("屬性 {$name} 為唯讀");
}
$this->data[$name] = $value;
}
public function __isset(string $name): bool {
return isset($this->data[$name]);
}
public function __unset(string $name) {
if (in_array($name, $this->readonly, true)) {
throw new Exception("不可刪除唯讀屬性 {$name}");
}
unset($this->data[$name]);
}
}
$e = new DynamicEntity();
$e->id = 1; // 寫入
$e->name = 'Test'; // 寫入
echo $e->name; // 讀取
// $e->id = 2; // 拋出例外:唯讀
// unset($e->id); // 拋出例外:不可刪除
?>
interface 定義契約,方法隱含 public,可定義常量。abstract class 可包含抽象方法(無主體)與具體實作,不可實例化。trait) 實現橫向代碼復用,解決單一繼承限制。掌握 PHP 類的完整語法:可見性控制封裝邊界、靜態成員屬於類、Final 防止意外覆寫、魔術方法賦予物件動態行為。善用 __get/__set 實作虛擬屬性、__invoke 實作可呼叫物件、__serialize/__unserialize 控制序列化,能編寫出既符合封裝原則又具靈活性的現代 PHP 代碼。