引言
在PHP面向对象编程中,抽象类、接口和类型声明是构建可扩展、可维护应用程序的重要工具。本文将深入探讨这些概念,展示它们如何帮助开发者创建更健壮的代码结构。
抽象类(Abstract Classes)
抽象类是不能被实例化的类,它定义了子类必须实现的方法模板。
基本抽象类示例
abstract class Animal {
protected $name;
public function __construct($name) {
$this->name = $name;
}
abstract public function makeSound();
public function getName() {
return $this->name;
}
}
class Dog extends Animal {
public function makeSound() {
return "Woof! Woof!";
}
}
class Cat extends Animal {
public function makeSound() {
return "Meow!";
}
}
$dog = new Dog("Buddy");
$cat = new Cat("Whiskers");
echo $dog->getName() . " says: " . $dog->makeSound() . "\n";
// 输出: Buddy says: Woof! Woof!
echo $cat->getName() . " says: " . $cat->makeSound() . "\n";
// 输出: Whiskers says: Meow!
抽象类的高级用法
abstract class Shape {
abstract public function area();
abstract public function perimeter();
public function compareArea(Shape $otherShape) {
return $this->area() <=> $otherShape->area();
}
public function __toString() {
return get_class($this) . " - Area: " . $this->area() .
", Perimeter: " . $this->perimeter();
}
}
class Rectangle extends Shape {
private $width;
private $height;
public function __construct($width, $height) {
$this->width = $width;
$this->height = $height;
}
public function area() {
return $this->width * $this->height;
}
public function perimeter() {
return 2 * ($this->width + $this->height);
}
}
class Circle extends Shape {
private $radius;
public function __construct($radius) {
$this->radius = $radius;
}
public function area() {
return pi() * pow($this->radius, 2);
}
public function perimeter() {
return 2 * pi() * $this->radius;
}
}
$rectangle = new Rectangle(5, 10);
$circle = new Circle(7);
echo $rectangle . "\n";
// 输出: Rectangle - Area: 50, Perimeter: 30
echo $circle . "\n";
// 输出: Circle - Area: 153.9380400259, Perimeter: 43.982297150257
$result = $rectangle->compareArea($circle);
echo $result == -1 ? "Rectangle is smaller" : ($result == 0 ? "Equal" : "Rectangle is larger");
// 输出: Rectangle is smaller
接口(Interfaces)
接口定义了一组方法契约,实现类必须遵循这些契约。
基本接口示例
interface Logger {
public function log($message);
}
class FileLogger implements Logger {
private $filePath;
public function __construct($filePath) {
$this->filePath = $filePath;
}
public function log($message) {
file_put_contents($this->filePath, date('Y-m-d H:i:s') . " - " . $message . "\n", FILE_APPEND);
}
}
class DatabaseLogger implements Logger {
private $connection;
public function __construct(PDO $connection) {
$this->connection = $connection;
}
public function log($message) {
$stmt = $this->connection->prepare("INSERT INTO logs (message, created_at) VALUES (?, NOW())");
$stmt->execute([$message]);
}
}
function processOrder(Logger $logger) {
// 处理订单逻辑...
$logger->log("Order processed successfully");
}
$fileLogger = new FileLogger('app.log');
$dbLogger = new DatabaseLogger(new PDO('mysql:host=localhost;dbname=test', 'user', 'password'));
processOrder($fileLogger);
processOrder($dbLogger);
接口继承与多接口实现
interface Drawable {
public function draw();
}
interface Scalable {
public function scale($factor);
}
interface Transformable extends Drawable, Scalable {
public function rotate($degrees);
}
class Graphic implements Transformable {
public function draw() {
echo "Drawing graphic...\n";
}
public function scale($factor) {
echo "Scaling by factor {$factor}...\n";
}
public function rotate($degrees) {
echo "Rotating by {$degrees} degrees...\n";
}
}
$graphic = new Graphic();
$graphic->draw();
$graphic->scale(1.5);
$graphic->rotate(45);
类型声明(Type Declarations)
PHP7+引入了更严格的类型声明系统,提高了代码的可靠性和可预测性。
标量类型声明
declare(strict_types=1); // 严格类型模式
class Calculator {
public static function add(float $a, float $b): float {
return $a + $b;
}
public static function concat(string $a, string $b): string {
return $a . $b;
}
public static function isEven(int $number): bool {
return $number % 2 === 0;
}
}
echo Calculator::add(5.5, 3.2) . "\n"; // 输出: 8.7
echo Calculator::concat("Hello", " World") . "\n"; // 输出: Hello World
var_dump(Calculator::isEven(4)); // 输出: bool(true)
// Calculator::add("5", "3"); // 在严格模式下会抛出TypeError
返回类型声明
class UserRepository {
private $users = [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob']
];
public function findById(int $id): ?array {
foreach ($this->users as $user) {
if ($user['id'] === $id) {
return $user;
}
}
return null;
}
public function getAllNames(): array {
return array_column($this->users, 'name');
}
public function createUser(string $name): void {
$this->users[] = ['id' => count($this->users) + 1, 'name' => $name];
}
}
$repo = new UserRepository();
var_dump($repo->findById(1)); // 输出用户Alice的数据
var_dump($repo->findById(99)); // 输出: NULL
print_r($repo->getAllNames()); // 输出: Array ( [0] => Alice [1] => Bob )
$repo->createUser("Charlie");
对象类型声明与接口类型提示
interface PaymentGateway {
public function charge(float $amount): bool;
}
class CreditCardPayment implements PaymentGateway {
public function charge(float $amount): bool {
echo "Charging \${$amount} via Credit Card...\n";
// 实际支付处理逻辑
return true;
}
}
class PayPalPayment implements PaymentGateway {
public function charge(float $amount): bool {
echo "Charging \${$amount} via PayPal...\n";
// 实际支付处理逻辑
return true;
}
}
class PaymentProcessor {
public function process(PaymentGateway $gateway, float $amount): bool {
return $gateway->charge($amount);
}
}
$processor = new PaymentProcessor();
$creditCard = new CreditCardPayment();
$paypal = new PayPalPayment();
$processor->process($creditCard, 100.50);
$processor->process($paypal, 75.25);
抽象类与接口的结合使用
abstract class DatabaseModel {
abstract protected static function getTableName(): string;
public static function all(): array {
$table = static::getTableName();
// 模拟数据库查询
return "SELECT * FROM {$table}";
}
public static function find(int $id): ?array {
$table = static::getTableName();
// 模拟数据库查询
return "SELECT * FROM {$table} WHERE id = {$id}";
}
}
interface Timestampable {
public function getCreatedAt(): DateTime;
public function getUpdatedAt(): DateTime;
}
interface SoftDeletable {
public function isDeleted(): bool;
public function softDelete(): void;
}
class User extends DatabaseModel implements Timestampable, SoftDeletable {
protected static function getTableName(): string {
return 'users';
}
private $createdAt;
private $updatedAt;
private $deleted = false;
public function __construct() {
$this->createdAt = new DateTime();
$this->updatedAt = new DateTime();
}
public function getCreatedAt(): DateTime {
return $this->createdAt;
}
public function getUpdatedAt(): DateTime {
return $this->updatedAt;
}
public function isDeleted(): bool {
return $this->deleted;
}
public function softDelete(): void {
$this->deleted = true;
$this->updatedAt = new DateTime();
}
}
$user = new User();
var_dump(User::all()); // 输出: string(17) "SELECT * FROM users"
var_dump($user->getCreatedAt()); // 输出当前时间
$user->softDelete();
var_dump($user->isDeleted()); // 输出: bool(true)
类型声明的高级应用:联合类型与交集类型
PHP8引入了联合类型和交集类型,进一步增强了类型系统的表达能力。
联合类型(Union Types)
class Product {
public function calculateShippingCost(int|float $weight): float {
if (is_int($weight)) {
return $weight * 0.5;
}
return $weight * 0.75;
}
public function setDiscount(string|DateTime $discountEnd): void {
if (is_string($discountEnd)) {
$discountEnd = new DateTime($discountEnd);
}
echo "Discount ends at: " . $discountEnd->format('Y-m-d') . "\n";
}
}
$product = new Product();
echo $product->calculateShippingCost(10) . "\n"; // 输出: 5
echo $product->calculateShippingCost(7.5) . "\n"; // 输出: 5.625
$product->setDiscount("2023-12-31");
$product->setDiscount(new DateTime("2023-06-30"));
交集类型(Intersection Types)
interface Loggable {
public function log(string $message): void;
}
interface Cacheable {
public function cache(string $key, $value): void;
public function getFromCache(string $key);
}
class LoggerCache implements Loggable, Cacheable {
private $logs = [];
private $cache = [];
public function log(string $message): void {
$this->logs[] = $message;
}
public function cache(string $key, $value): void {
$this->cache[$key] = $value;
}
public function getFromCache(string $key) {
return $this->cache[$key] ?? null;
}
public function getLogs(): array {
return $this->logs;
}
}
function processData(Loggable&Cacheable $service, array $data): void {
foreach ($data as $key => $value) {
$service->cache($key, $value);
$service->log("Cached value for key: {$key}");
}
}
$service = new LoggerCache();
processData($service, ['name' => 'Alice', 'age' => 30]);
print_r($service->getFromCache('name')); // 输出: Alice
print_r($service->getLogs());
/* 输出:
Array
(
[0] => Cached value for key: name
[1] => Cached value for key: age
)
*/
结语
抽象类、接口和类型声明是PHP面向对象编程中强大的工具组合。抽象类提供了部分实现和强制子类实现特定方法的能力,接口定义了清晰的契约,而类型声明则增强了代码的可靠性和可维护性。
在实际开发中,建议:
- 使用接口定义行为契约
- 使用抽象类提供通用实现
- 尽可能使用类型声明来提高代码质量
- 在PHP8+项目中利用联合类型和交集类型简化代码
在下一篇文章中,我们将探讨PHP中的特性(Traits)、匿名类和对象比较等高级面向对象特性,这些将进一步扩展你的PHP面向对象编程能力。