Skip to content

抽象类与接口

抽象类和接口是实现多态和规范子类行为的重要机制

php
<?php
// 抽象类 - 不能被实例化,只能被继承
abstract class Animal {
  protected $name;

  public function __construct($name) {
    $this->name = $name;
  }

  // 抽象方法 - 没有方法体,必须在子类中实现
  abstract public function makeSound();

  // 普通方法
  public function getName() {
    return $this->name;
  }
}

// 接口 - 定义规范,可以被多个类实现
interface Pet {
  public function play();
  public function feed();
}

// 接口可以继承其他接口
interface ShowPet extends Pet {
  public function performTrick();
}

// 类可以实现多个接口,但只能继承一个抽象类
class Dog extends Animal implements ShowPet {
  public function makeSound() {
    return "汪汪!";
  }

  public function play() {
    return "狗在玩球";
  }

  public function feed() {
    return "喂狗粮";
  }

  public function performTrick() {
    return "狗在表演技巧";
  }
}

class Cat extends Animal implements Pet {
  public function makeSound() {
    return "喵喵!";
  }

  public function play() {
    return "猫在玩毛线球";
  }

  public function feed() {
    return "喂猫粮";
  }
}

$dog = new Dog("大黄");
$cat = new Cat("小花");

echo $dog->getName() . "说: " . $dog->makeSound() . "\n"; // 大黄说: 汪汪!
echo $dog->performTrick() . "\n"; // 狗在表演技巧

echo $cat->getName() . "说: " . $cat->makeSound() . "\n"; // 小花说: 喵喵!

// 类型检查
function petSound(Animal $animal) {
  echo $animal->getName() . "发出声音: " . $animal->makeSound() . "\n";
}

petSound($dog); // 大黄发出声音: 汪汪!
petSound($cat); // 小花发出声音: 喵喵!

// 接口类型检查
function interactWithPet(Pet $pet) {
  echo $pet->play() . "\n";
  echo $pet->feed() . "\n";
}

interactWithPet($dog); // 狗在玩球 \n 喂狗粮
interactWithPet($cat); // 猫在玩毛线球 \n 喂猫粮

Trait 特性

Trait 是 PHP 5.4 引入的特性,用于解决单继承语言的局限性

php
<?php
// 可复用的代码单元
trait Loggable {
  public function log($message) {
    echo "Log: " . $message . "\n";
  }

  private function formatLogMessage($message) {
    return "[" . date('Y-m-d H:i:s') . "] " . $message;
  }
}

trait Cacheable {
  public function cache($key, $value) {
    echo "Caching $key\n";
    // 实际应用中这里会保存到缓存系统
    return true;
  }

  public function getFromCache($key) {
    echo "Getting $key from cache\n";
    // 实际应用中这里会从缓存系统获取
    return null;
  }
}

class Database {
  use Loggable, Cacheable {
    // 解决方法冲突
    Loggable::log insteadof Cacheable;
    Cacheable::log as cacheLog;
  }

  public function query($sql) {
    $this->log("Executing query: $sql");
    // 实际查询代码...
    return [];
  }
}

class UserRepository {
  use Loggable;

  public function findUser($id) {
    $this->log("Finding user with ID: $id");
    // 实际查找代码...
    return ["id" => $id, "name" => "User $id"];
  }
}

$db = new Database();
$db->query("SELECT * FROM users");
$db->cache("user_1", ["name" => "张三"]);

// 由于方法名冲突,我们使用别名
// $db->log("Database log"); // 使用Loggable的log
// $db->cacheLog("Cache log"); // 使用Cacheable的log的别名

$repo = new UserRepository();
$repo->findUser(1);

// Trait 的可见性
trait VisibleTrait {
  public function publicMethod() {
    return "Public method";
  }

  protected function protectedMethod() {
    return "Protected method";
  }

  private function privateMethod() {
    return "Private method";
  }

  // Trait 中可以使用抽象方法
  abstract public function abstractMethod();

  // Trait 中可以使用静态方法
  public static function staticMethod() {
    return "Static method";
  }
}

class MyClass {
  use VisibleTrait;

  // 必须实现 Trait 中定义的抽象方法
  public function abstractMethod() {
    return "Implemented abstract method";
  }
}

$obj = new MyClass();
echo $obj->publicMethod() . "\n"; // Public method
// echo $obj->protectedMethod(); // 无法在类外部访问
// echo $obj->privateMethod(); // 无法在类外部访问
echo $obj->abstractMethod() . "\n"; // Implemented abstract method
echo MyClass::staticMethod() . "\n"; // Static method

Released under the MIT License.