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

PHP 物件導向程式設計(OOP)完整指南:類別、繼承、介面、Trait 與進階特性

     編輯:PHP 入門

PHP 物件導向程式設計(OOP)完整指南

PHP 5 引入完整物件模型,PHP 7/8 持續強化效能與語法。OOP 將資料與行為封裝於類別,支援封裝、繼承、多型,是構建大型可維護系統的基石。本文系統整理 PHP OOP 核心概念與實務應用。

核心概念

術語說明
類別物件的藍圖,定義屬性(變數)與方法(函數)
物件類別的實例,擁有獨立狀態
屬性類別內部變數,可設可視性
方法類別內部函數,操作物件資料
建構子__construct(),實例化時自動呼叫初始化
解構子__destruct(),物件銷毀前呼叫清理
繼承子類別重用父類別程式碼,extends
多型相同介面不同實作,執行時決定具體行為
介面定義契約,implements 強制實作方法
Trait程式碼復用單位,use 組合進類別
抽象類別不可實例化,含抽象方法強制子類別實作

類別定義與實例化

<?php
class User {
    // 屬性(可視性:public/protected/private)
    public string $name;
    protected string $email;
    private string $passwordHash;
    public readonly string $createdAt; // PHP 8.1+ 唯讀屬性
    
    // 建構子(PHP 8.0+ 提升屬性語法)
    public function __construct(
        public string $username, // 自動建立並賦值屬性
        string $email,
        string $password
    ) {
        $this->email = $email;
        $this->passwordHash = password_hash($password, PASSWORD_DEFAULT);
        $this->createdAt = (new DateTime())->format('c');
    }
    
    // 方法
    public function getEmail(): string {
        return $this->email;
    }
    
    public function verifyPassword(string $password): bool {
        return password_verify($password, $this->passwordHash);
    }
    
    // 魔術方法:序列化控制
    public function __sleep(): array {
        return ['username', 'email', 'createdAt']; // 排除 passwordHash
    }
}

// 實例化
$user = new User('john_doe', 'john@example.com', 'secret123');
echo $user->username;      // john_doe (public)
echo $user->getEmail();    // john@example.com
// $user->email;           // Error: protected
// $user->passwordHash;    // Error: private
?>

可視性控制

關鍵字類別內部子類別外部
public✓✓✓
protected✓✓✗
private✓✗✗
<?php
class ParentClass {
    public $pub = 'public';
    protected $pro = 'protected';
    private $pri = 'private';
    
    public function printAll() {
        echo $this->pub . ' ' . $this->pro . ' ' . $this->pri;
    }
}

class ChildClass extends ParentClass {
    public function testAccess() {
        echo $this->pub;    // ✓
        echo $this->pro;    // ✓
        // echo $this->pri; // Error
    }
}

$obj = new ChildClass();
$obj->pub;      // ✓
// $obj->pro;   // Error
// $obj->pri;   // Error
$obj->printAll(); // public protected private
$obj->testAccess(); // public protected

靜態成員

<?php
class Counter {
    private static int $count = 0;
    public static string $version = '1.0';
    
    public static function increment(): int {
        return ++self::$count;
    }
    
    public static function getCount(): int {
        return self::$count;
    }
}

Counter::increment();
Counter::increment();
echo Counter::getCount(); // 2
echo Counter::$version;   // 1.0

// 靜態方法中不可用 $this
// 晚期靜態綁定 (PHP 5.3+)
class A {
    public static function who() { echo __CLASS__; }
    public static function test() { static::who(); } // 晚期綁定
}
class B extends A {
    public static function who() { echo __CLASS__; }
}
B::test(); // B (而非 A)

常數

<?php
class Config {
    public const API_URL = 'https://api.example.com';
    public const TIMEOUT = 30;
    // PHP 8.1+ final 常數不可覆寫
    final public const VERSION = '2.0';
}

// 存取
echo Config::API_URL;
// 動態存取 (PHP 5.3+)
$class = 'Config';
echo $class::API_URL;

繼承與方法覆寫

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

class Dog extends Animal {
    public function speak(): string { // 覆寫
        return "{$this->name} 汪汪叫";
    }
    
    public function fetch(): string {
        return "{$this->name} 撿回球";
    }
}

$dog = new Dog('旺財');
echo $dog->speak();   // 旺財 汪汪叫
echo $dog->fetch();   // 旺財 撿回球
echo $dog->getName(); // 旺財

抽象類別

<?php
abstract class PaymentGateway {
    protected string $merchantId;
    
    public function __construct(string $merchantId) {
        $this->merchantId = $merchantId;
    }
    
    // 抽象方法:子類別必須實作
    abstract public function charge(float $amount, string $currency): bool;
    abstract public function refund(string $transactionId): bool;
    
    // 具體方法:子類別可繼承或覆寫
    protected function log(string $message): void {
        error_log("[{$this->merchantId}] $message");
    }
}

class StripeGateway extends PaymentGateway {
    public function charge(float $amount, string $currency): bool {
        $this->log("Stripe 扣款 $amount $currency");
        // API 呼叫...
        return true;
    }
    
    public function refund(string $transactionId): bool {
        $this->log("Stripe 退款 $transactionId");
        return true;
    }
}

// $gateway = new PaymentGateway(); // Error: 抽象類別不可實例化
$stripe = new StripeGateway('merch_123');
$stripe->charge(100, 'USD');

介面

<?php
interface LoggerInterface {
    public function log(string $level, string $message): void;
    public function emergency(string $message): void;
}

interface CacheInterface {
    public function get(string $key): mixed;
    public function set(string $key, mixed $value, int $ttl): bool;
}

// 多重實作
class RedisLogger implements LoggerInterface, CacheInterface {
    public function log(string $level, string $message): void {
        // Redis 列表儲存日誌
    }
    
    public function emergency(string $message): void {
        // 立即告警
    }
    
    public function get(string $key): mixed { /* ... */ }
    public function set(string $key, mixed $value, int $ttl): bool { /* ... */ }
}

// 介面作為型別提示
function processOrder(Order $order, LoggerInterface $logger): void {
    $logger->log('info', "處理訂單 {$order->id}");
}

Trait 程式碼復用

<?php
trait Timestampable {
    public DateTime $createdAt;
    public DateTime $updatedAt;
    
    public function setTimestamps(): void {
        $now = new DateTime();
        $this->createdAt = $this->createdAt ?? $now;
        $this->updatedAt = $now;
    }
}

trait SoftDeletes {
    public ?DateTime $deletedAt = null;
    
    public function delete(): void {
        $this->deletedAt = new DateTime();
    }
    
    public function isDeleted(): bool {
        return $this->deletedAt !== null;
    }
    
    // 衝突解決
    public function restore(): void {
        $this->deletedAt = null;
    }
}

class Article {
    use Timestampable, SoftDeletes {
        // 解決方法名衝突
        SoftDeletes::restore insteadof Timestampable;
        Timestampable::setTimestamps as traitSetTimestamps;
    }
    
    public string $title;
    public string $content;
}

$article = new Article();
$article->title = 'PHP OOP 指南';
$article->setTimestamps();
$article->delete();
echo $article->isDeleted() ? '已刪除' : '正常';

魔術方法

方法觸發時機
__construct()new 實例化
__destruct()物件銷毀/腳本結束
__call($name, $args)呼叫不可存取方法
__callStatic($name, $args)靜態呼叫不可存取方法
__get($name)讀取不可存取屬性
__set($name, $value)寫入不可存取屬性
__isset($name)isset() 檢查不可存取屬性
__unset($name)unset() 不可存取屬性
__sleep()serialize()
__wakeup()unserialize()
__toString()物件作為字串使用
__invoke()物件作為函數呼叫
__clone()clone 複製物件
__debugInfo()var_dump()
__serialize()serialize() (PHP 7.4+)
__unserialize()unserialize() (PHP 7.4+)

型別宣告與嚴格模式

<?php
declare(strict_types=1); // 檔案頂部啟用嚴格模式

class Calculator {
    // 參數/回傳型別
    public function add(int|float $a, int|float $b): int|float { // PHP 8.0+ 聯合型別
        return $a + $b;
    }
    
    // 回傳型別聲明
    public function getName(): string { /* ... */ }
    
    // void 明確無回傳
    public function log(string $msg): void { /* ... */ }
    
    // never 不會返回 (PHP 8.1+)
    public function throwError(): never {
        throw new Exception('Error');
    }
    
    // mixed 任意型別 (PHP 8.0+)
    public function process(mixed $data): mixed { /* ... */ }
}

唯讀屬性與類別

<?php
// PHP 8.1+ 唯讀屬性(初始化後不可修改)
class Config {
    public function __construct(
        public readonly string $apiKey,
        public readonly int $timeout = 30
    ) {}
}

// PHP 8.2+ 唯讀類別(所有屬性隱含 readonly)
readonly class DTO {
    public function __construct(
        public string $id,
        public string $name,
        public DateTime $createdAt
    ) {}
}

列舉

<?php
// PHP 8.1+ 列舉
enum Status: string {
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';
    
    public function label(): string {
        return match($this) {
            self::Draft => '草稿',
            self::Published => '已發布',
            self::Archived => '已封存',
        };
    }
}

// 使用
$status = Status::Published;
echo $status->value;      // published
echo $status->label();    // 已發布

// 型別提示
function setStatus(Status $status): void { /* ... */ }

最佳實踐原則

  1. 單一職責:類別只有一個變更理由
  2. 開放封閉:擴展開放、修改關閉(介面+實作)
  3. 里氏替換:子類別可替換父類別不破壞行為
  4. 介面隔離:多個小介面優於單一大介面
  5. 依賴反轉:依賴抽象(介面)而非具體類別
  6. 組合優於繼承:Trait、策略模式、裝飾模式替代深層繼承
  7. 不可變物件:readonly 屬性、DTO、值物件減少狀態錯誤
  8. 嚴格型別:declare(strict_types=1) 捕獲型別錯誤

PHP OOP 經歷多版本演進,已具備現代語言完整特性。善用型別系統、可視性控制、介面契約、Trait 組合、魔術方法,配合 SOLID 原則,能構建優雅、可測試、可維護的企業級應用。

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