| 修飾詞 | 類別內部 | 子類別 | 外部程式碼 | 預設值 |
|---|---|---|---|---|
public |
✅ | ✅ | ✅ | 省略修飾詞時的預設 |
protected |
✅ | ✅ | ❌ | — |
private |
✅ | ❌(但可在子類重新定義同名屬性) | ❌ | — |
核心概念: 封裝將「資料(屬性)」與「行為(方法)」包裹在類別內部,透過可見性控制存取權限,達到「資訊隱藏」與「介面穩定」雙重目的。
<?php
class MyClass {
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
}
$obj = new MyClass();
echo $obj->public; // ✅ 輸出 Public
// echo $obj->protected; // ❌ Fatal error: Cannot access protected property
// echo $obj->private; // ❌ Fatal error: Cannot access private property
?>
<?php
class ParentClass {
protected $p = 'parent protected';
private $v = 'parent private';
}
class ChildClass extends ParentClass {
public function test() {
echo $this->p; // ✅ 可存取 protected
// echo $this->v; // ❌ 無法存取 private
$this->v = 'child private'; // ✅ 允許在子類「重新定義」同名 private 屬性
echo $this->v; // 輸出 'child private'(屬於子類自己的私有屬性)
}
}
$c = new ChildClass();
$c->test();
?>
關鍵: private 不會被繼承,但子類可定義同名屬性,兩者互不干擾,各佔記憶體空間。
<?php
class BankAccount {
private float $balance = 0.0;
private array $transactions = [];
// 唯讀存取器
public function getBalance(): float { return $this->balance; }
public function getTransactions(): array { return $this->transactions; }
// 受控修改:存款
public function deposit(float $amount): bool {
if ($amount <= 0) return false;
$this->balance += $amount;
$this->transactions[] = ['type'=>'deposit','amount'=>$amount,'time'=>time()];
return true;
}
// 受控修改:提款
public function withdraw(float $amount): bool {
if ($amount <= 0 || $amount > $this->balance) return false;
$this->balance -= $amount;
$this->transactions[] = ['type'=>'withdraw','amount'=>$amount,'time'=>time()];
return true;
}
}
$acc = new BankAccount();
$acc->deposit(1000);
$acc->withdraw(300);
// $acc->balance = -9999; // ❌ 編譯錯誤:無法從外部竄改
echo $acc->getBalance(); // 700
print_r($acc->getTransactions());
若需動態屬性或委派存取,可實作魔術方法(謹慎使用,影響 IDE 提示與效能):
<?php
class DynamicEntity {
private array $data = [];
public function __get(string $name) {
return $this->data[$name] ?? null;
}
public function __set(string $name, $value): void {
$this->data[$name] = $value;
}
public function __isset(string $name): bool {
return isset($this->data[$name]);
}
public function __unset(string $name): void {
unset($this->data[$name]);
}
}
$e = new DynamicEntity();
$e->foo = 'bar'; // 呼叫 __set
echo $e->foo; // 呼叫 __get
unset($e->foo); // 呼叫 __unset
封裝是物件導向的基石。遵循「屬性預設 private、提供 public 存取器、子類需求用 protected、謹慎使用魔術方法」原則,即能建構出高內聚、低耦合、易維護的類別。PHP 8.1+ 新增 readonly 關鍵字,更能在語言層面強制不可變性,推薦優先使用。