01. 类和对象基础
PHP 从诞生起就支持面向对象,但随着版本迭代 OOP 特性越来越完善。用 class 定义类,new 创建对象,-> 访问属性和方法。$this 指当前对象,self:: 指当前类。构造函数 __construct 在 new 时自动调用,析构函数 __destruct 在对象销毁时调用。
php
<?php
class User {
public string $name;
private int $age;
public function __construct(string $name, int $age) {
$this->name = $name;
$this->age = $age;
}
public function getAge(): int {
return $this->age;
}
public function __destruct() {
echo "{$this->name} 被销毁了\n";
}
}
$user = new User("小明", 18);
echo $user->name; // 小明
echo $user->getAge(); // 18PHP 8 引入了构造函数属性提升,__construct(public string $name) 一行代替声明加赋值。
02. 访问修饰符和继承
PHP 有三种访问修饰符:public 到处都能访问,protected 自己和子类能访问,private 只有自己类内部能访问。继承用 extends,单继承。子类重写父类方法可以加 override 标注(PHP 8.3)。parent:: 调用父类方法。final 阻止继承或重写。
php
<?php
class Animal {
protected string $name;
public function __construct(string $name) {
$this->name = $name;
}
public function speak(): string {
return "...";
}
}
class Dog extends Animal {
public function speak(): string {
return parent::speak() . " 汪汪";
}
public function getName(): string {
return $this->name; // protected 可以访问
}
}
final class Cat extends Animal {
// Cat 不能再被继承
}
$dog = new Dog("旺财");
echo $dog->speak(); // ... 汪汪03. 抽象类和接口
抽象类用 abstract 修饰,不能直接实例化,子类必须实现所有抽象方法。接口用 interface 定义,只声明方法签名不实现,类通过 implements 实现接口。PHP 支持多接口实现。接口是是什么的契约,抽象类是共享基础实现。
php
<?php
interface Loggable {
public function log(): string;
}
abstract class BaseModel {
protected int $id;
abstract public function table(): string;
public function getId(): int {
return $this->id;
}
}
class User extends BaseModel implements Loggable {
public function table(): string {
return "users";
}
public function log(): string {
return "用户 {$this->id} 操作记录";
}
}
$user = new User();
echo $user->table(); // users
echo $user->log(); // 用户 0 操作记录PHP 支持多接口实现,用逗号分隔:class Foo implements A, B, C {}
04. Trait 代码复用
PHP 不能多继承,但可以用 Trait 在多个类之间共享方法。trait 定义一组方法,用 use 关键字引入类中。多个 trait 可以用逗号引入。冲突时用 insteadof 选择用哪个,as 起别名。Trait 解决了单继承的复用限制,比复制粘贴代码优雅。
php
<?php
trait Timestamps {
public function createdAt(): string {
return date("Y-m-d H:i:s");
}
public function updatedAt(): string {
return date("Y-m-d H:i:s");
}
}
trait SoftDelete {
public function delete(): void {
echo "软删除\n";
}
}
class Article {
use Timestamps, SoftDelete;
public string $title;
}
$article = new Article();
echo $article->createdAt(); // 2024-01-01 12:00:00
$article->delete(); // 软删除Trait 适合横向的代码共享(如日志、时间戳、软删除),继承适合纵向的是否关系。
05. 魔术方法和命名空间
PHP 的魔术方法以 __ 开头,在特定时机自动调用。__toString 转字符串,__get/__set 访问不存在的属性时触发,__call/__callStatic 调用不存在的方法时触发。命名空间 namespace 避免类名冲突,use 导入,类似 Python 的 import。
php
<?php
namespace App\Models;
class User {
private array $data = [];
public function __get(string $name) {
return $this->data[$name] ?? null;
}
public function __set(string $name, $value): void {
$this->data[$name] = $value;
}
public function __toString(): string {
return json_encode($this->data);
}
public static function __callStatic(string $name, array $args) {
echo "调用不存在的静态方法: {$name}\n";
}
}
$user = new User();
$user->email = "[email protected]"; // __set 被调用
echo $user->email; // __get 被调用
echo $user; // __toString 被调用
User::findByEmail("..."); // __callStatic 被调用魔术方法会让代码变得隐晦,不要滥用。尤其是 __get/__set 会让 IDE 无法做自动补全。
知识测验
第 1/4 题正确 0
PHP 中访问当前对象的属性用什么?
下一节
下一节 数据库操作