PHP 面向对象编程:类、对象、继承一篇搞懂
为什么需要面向对象
当代码超过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解决单继承限制,实现代码横向复用