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

PHP 面向對象深度解析:封裝性、魔術方法、繼承、訪問控制與關鍵字

     編輯:PHP 相關知識

封裝性:資訊隱藏的核心

將屬性與方法包裹在類內部,對外僅暴露必要介面。三大訪問修飾符:

修飾符類內部子類外部用途
public✅✅✅公開 API
protected✅✅❌內部/繼承協作
private✅❌❌核心邏輯隔離

四大屬性魔術方法 (Property Overloading)

當訪問不可見屬性 (不存在、或權限不足) 時自動觸發:

方法觸發時機簽名典型用途
__get讀取不可見屬性__get(string $name): mixed延遲載入、代理、計算屬性
__set寫入不可見屬性__set(string $name, mixed $value): void驗證、日誌、觸發事件
__issetisset()/empty() 檢查不可見屬性__isset(string $name): bool虛擬屬性存在性判斷
__unsetunset() 不可見屬性__unset(string $name): void清理快取、解除綁定

實戰範例:動態屬性代理

<?php
class User {
  private array $data = [];
  private array $loaded = [];
  
  public function __get(string $name) {
    if (isset($this->data[$name])) return $this->data[$name];
    
    // 延遲從資料庫載入
    if (in_array($name, ['posts', 'comments', 'profile'])) {
      $this->data[$name] = $this->loadRelation($name);
      return $this->data[$name];
    }
    
    throw new Exception("屬性不存在: $name");
  }
  
  public function __set(string $name, mixed $value) {
    if ($name === 'email' && !filter_var($value, FILTER_VALIDATE_EMAIL)) {
      throw new Exception("無效 Email");
    }
    $this->data[$name] = $value;
    $this->markDirty($name);
  }
  
  public function __isset(string $name): bool {
    return isset($this->data[$name]) || in_array($name, ['posts', 'comments', 'profile']);
  }
  
  public function __unset(string $name) {
    unset($this->data[$name]);
    $this->markDirty($name);
  }
  
  private function loadRelation(string $name): array {
    // 模擬 DB 查詢
    return ["loaded_$name" => true];
  }
  
  private function markDirty(string $name) { /* ... */ }
}

$user = new User();
$user->email = 'test@example.com'; // __set 驗證
echo $user->posts;                 // __get 延遲載入
var_dump(isset($user->profile));   // __isset
unset($user->email);               // __unset

繼承:extends 關鍵字

<?php
class Animal {
  protected string $name;
  public function __construct(string $name) { $this->name = $name; }
  public function speak(): string { return "{$this->name} 發出聲音"; }
}

class Dog extends Animal {
  public function speak(): string { // 方法覆寫
    return parent::speak() . " - 汪汪!"; // 呼叫父類方法
  }
  public function fetch(): string { return "{$this->name} 撿回球"; }
}

$dog = new Dog('旺財');
echo $dog->speak(); // 旺財 發出聲音 - 汪汪!
echo $dog->fetch(); // 旺財 撿回球

繼承規則

  • 子類繼承父類所有 public/protected 成員
  • private 成員不繼承 (子類不可見)
  • 建構子不繼承,子類需自行定義並呼叫 parent::__construct()
  • PHP 不支援多重繼承,使用 trait 組合行為

方法覆寫與 final 關鍵字

<?php
class BaseService {
  final public function execute(): void { // 禁止覆寫
    $this->before();
    $this->doExecute();
    $this->after();
  }
  
  protected function before(): void { echo "開始\n"; }
  protected function after(): void { echo "結束\n"; }
  
  // 子類必須實現
  abstract protected function doExecute(): void;
}

class UserService extends BaseService {
  protected function doExecute(): void { echo "處理用戶邏輯\n"; }
  // 不能覆寫 execute()
}

static 靜態成員:類層級共享

特性說明
儲存位置類記憶體區,非物件實例
訪問方式ClassName::$prop、ClassName::method()、self::$prop、static::$prop (晚期靜態綁定)
共享特性所有實例共享同一份值
限制靜態方法中 不可用 $this、self:: 僅限當前類、static:: 支援繼承多態

晚期靜態綁定 (LSB) 示例

<?php
class Model {
  protected static string $table = 'base';
  
  public static function getTable(): string {
    return static::$table; // LSB: 取得實際調用類的屬性
  }
}

class User extends Model {
  protected static string $table = 'users';
}

echo Model::getTable(); // base
echo User::getTable();  // users (非 self::$table 會輸出 base)

const 類常數:不可變值

  • 聲明時必須初始化,不可在建構子修改
  • 不需要 $ 符號
  • 訪問:ClassName::CONST_NAME、self::CONST_NAME
  • 介面也可定義常數
  • PHP 8.1+ 支援 final const 禁止子類覆寫
<?php
class Config {
  public const APP_NAME = 'MyApp';
  public const VERSION = '1.0.0';
  protected const INTERNAL_KEY = 'secret';
  
  public static function getKey(): string {
    return self::INTERNAL_KEY;
  }
}

echo Config::APP_NAME; // MyApp

完整實戰範例:結合所有特性

<?php
abstract class Repository {
  // 靜態快取,所有實例共享
  private static array $cache = [];
  
  // 常數配置
  protected const CACHE_TTL = 300;
  
  // 受保護屬性,子類可見
  protected PDO $db;
  
  // 私有屬性,僅本類可見
  private string $table;
  
  public function __construct(PDO $db, string $table) {
    $this->db = $db;
    $this->table = $table;
  }
  
  // final 公開 API,禁止覆寫
  final public function find(int $id): ?array {
    $key = "{$this->table}:$id";
    
    // __isset 魔術方法檢查快取
    if (isset(self::$cache[$key])) {
      return self::$cache[$key];
    }
    
    $data = $this->doFind($id);
    if ($data) self::$cache[$key] = $data;
    return $data;
  }
  
  // 抽象方法,子類必須實現
  abstract protected function doFind(int $id): ?array;
  
  // 靜態工廠方法
  public static function clearCache(): void {
    self::$cache = [];
  }
}

class UserRepository extends Repository {
  public function __construct(PDO $db) {
    parent::__construct($db, 'users');
  }
  
  protected function doFind(int $id): ?array {
    $stmt = $this->db->prepare("SELECT * FROM users WHERE id = ?");
    $stmt->execute([$id]);
    return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
  }
}

// 使用
$repo = new UserRepository($pdo);
$user = $repo->find(1); // 含快取邏輯
UserRepository::clearCache();

最佳實踐總結

  1. 預設 private:只在必要時放寬到 protected/public
  2. 組合優於繼承:用 trait/interface 組合行為,避免深層繼承樹
  3. final 預設:類和關鍵方法加 final,明確開放擴展點
  4. static 謹慎用:引入全域狀態,難測試、難並發,優先用實例屬性 + DI
  5. const 替代 define:命名空間隔離、IDE 支援、型別提示
  6. 魔術方法慎用:增加隱性行為,降低可讀性,文檔說明清楚
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved