PHP 面向对象编程:类、对象、继承一篇搞懂

小飞兽 PHP 12 次阅读 2026-07-16

为什么需要面向对象

当代码超过1000行,面向过程的写法会变得难以维护。OOP通过封装、继承、多态三大特性,让代码结构更清晰、复用性更高。

一、类与对象基础

1. 定义类

class User
{
    public string $name;
    public string $email;
    private int $age = 0;

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

public function getInfo(): string
{
return "{$this->name} ({$this->email})";
}
}

$user = new User('张三', 'zhangsan@example.com');
echo $user->getInfo();


2. 构造器属性提升(PHP 8+)


class User
{
public function __construct(
public string $name,
public string $email,
private int $age = 0
) {}
}

$user = new User('李四', 'lisi@example.com', 25);
echo $user->name; // 李四


二、继承


3. extends


class Animal
{
public function __construct(public string $name) {}
public function speak(): string { return '...'; }
}

class Dog extends Animal
{
public function speak(): string { return '汪汪!'; }
public function fetch(): string { return '捡球!'; }
}

class Cat extends Animal
{
public function speak(): string { return '喵~'; }
}

$dog = new Dog('旺财');
echo $dog->speak(); // 汪汪!


三、访问控制


PHP有三个访问修饰符:



    • public — 任意位置可访问

    • protected — 本类及子类可访问

    • private — 仅本类可访问


    四、接口(Interface)


    4. 定义与实现


    interface Payable
    {
    public function pay(float $amount): bool;
    public function refund(): bool;
    }

    class Alipay implements Payable
    {
    public function pay(float $amount): bool
    {
    echo '支付宝支付:¥' . $amount;
    return true;
    }
    public function refund(): bool
    {
    echo '支付宝退款';
    return true;
    }
    }

    function processPayment(Payable $payment, float $amount)
    {
    $payment->pay($amount);
    }


    5. 多接口


    interface Loggable { public function log(): string; }
    interface Cacheable { public function cache(): bool; }

    class Article implements Loggable, Cacheable
    {
    public function log(): string { return '日志'; }
    public function cache(): bool { return true; }
    }


    五、抽象类(Abstract)


    6. 抽象类


    抽象类不能直接实例化,但可以定义必须实现的方法:


    abstract class Shape
    {
    abstract public function area(): float;

    public function info(): string
    {
    return sprintf('面积:%.2f', $this->area());
    }
    }

    class Circle extends Shape
    {
    public function __construct(private float $radius) {}
    public function area(): float
    {
    return pi() * $this->radius ** 2;
    }
    }

    $circle = new Circle(5);
    echo $circle->info(); // 面积:78.54


    六、Trait


    7. Trait 复用代码


    PHP只支持单继承,Trait是横向复用的解决方案:


    trait Logger
    {
    abstract public function getName(): string;

    public function log(string $message): void
    {
    $time = date('Y-m-d H:i:s');
    echo "[{$time}] [{$this->getName()}] {$message}\n";
    }
    }

    class UserService
    {
    use Logger;

    public function getName(): string { return 'UserService'; }

    public function createUser(string $name): void
    {
    $this->log("创建用户:{$name}");
    }
    }


    七、静态成员


    8. static 属性和方法


    不依赖对象实例,整个类共享:


    class Counter
    {
    private static int $count = 0;

    public function __construct() { self::$count++; }

    public static function getCount(): int
    {
    return self::$count;
    }
    }

    $c1 = new Counter();
    $c2 = new Counter();
    echo Counter::getCount(); // 2


    八、常用魔术方法


    class User
    {
    public function __construct(private string $name) {}

    // 访问不存在的属性时调用
    public function __get(string $prop): mixed
    {
    return $this->$prop ?? null;
    }

    // serialize()时调用
    public function __sleep(): array
    {
    return ['name']; // 只序列化name属性
    }
    }


    九、实战:完整Service类


    class ArticleService
    {
    public function __construct(
    private ArticleRepository $repo,
    private CacheInterface $cache
    ) {}

    public function findById(int $id): ?Article
    {
    $cacheKey = "article:{$id}";

    if ($article = $this->cache->get($cacheKey)) {
    return $article;
    }

    $article = $this->repo->find($id);

    if ($article) {
    $this->cache->set($cacheKey, $article, 3600);
    }

    return $article;
    }
    }


    总结



    • 是模板,对象是实例

    • 继承用extends,接口用implements

    • Trait解决单继承限制,实现代码横向复用

  • protected让子类能访问父类成员,private完全封闭

  • 面向对象的核心是职责分离,每个类只做一件事