首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 類別封裝與可見性深度解析:public、protected、private 實戰應用

     編輯:PHP 相關知識

三大可見性修飾詞對照表

修飾詞類別內部子類別外部程式碼預設值
public ✅ ✅ ✅ 省略修飾詞時的預設
protected ✅ ✅ ❌ —
private ✅ ❌(但可在子類重新定義同名屬性) ❌ —

核心概念: 封裝將「資料(屬性)」與「行為(方法)」包裹在類別內部,透過可見性控制存取權限,達到「資訊隱藏」與「介面穩定」雙重目的。

程式碼實證:外部無法直接存取 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());

魔術方法補充:__get / __set 動態存取

若需動態屬性或委派存取,可實作魔術方法(謹慎使用,影響 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 關鍵字,更能在語言層面強制不可變性,推薦優先使用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved