跳到主要内容

PHP 面向对象

本章将介绍 PHP 面向对象编程的核心概念,包括类、对象、继承、接口等。

类与对象

定义类

使用 class 关键字定义类:

<?php
class Person {
// 属性
public $name;
public $age;

// 构造方法
public function __construct($name, $age) {
$this->name = $name;
$this->age = $age;
}

// 方法
public function greet() {
return "你好,我是" . $this->name;
}

// 析构方法
public function __destruct() {
echo "对象被销毁";
}
}
?>

创建对象

<?php
// 创建对象
$person = new Person("张三", 25);

// 访问属性
echo $person->name; // 张三

// 调用方法
echo $person->greet(); // 你好,我是张三

// PHP 8+ 无括号创建
$person = new Person;
?>

属性

<?php
class User {
// 公有属性(任何地方可访问)
public $name;

// 受保护属性(本类和子类可访问)
protected $email;

// 私有属性(仅本类可访问)
private $password;

// 静态属性
public static $count = 0;

// 类型声明属性(PHP 7.4+)
public int $age;
public string $city = "北京";

// 只读属性(PHP 8.1+)
public readonly string $id;

public function __construct(string $id) {
$this->id = $id;
self::$count++;
}
}
?>

方法

<?php
class Calculator {
// 公有方法
public function add($a, $b) {
return $a + $b;
}

// 受保护方法
protected function validate($num) {
return is_numeric($num);
}

// 私有方法
private function log($message) {
error_log($message);
}

// 静态方法
public static function multiply($a, $b) {
return $a * $b;
}

// 类型声明
public function divide(float $a, float $b): float {
return $a / $b;
}
}

// 调用静态方法
echo Calculator::multiply(3, 4); // 12
?>

$this 与 self

<?php
class Counter {
public $count = 0;
public static $total = 0;

public function increment() {
$this->count++; // 访问实例属性
self::$total++; // 访问静态属性
}

public static function getTotal() {
// return $this->count; // 错误!静态方法中不能使用 $this
return self::$total;
}
}
?>

构造与析构

构造方法

<?php
class User {
public $name;
public $age;

// PHP 8+ 构造器属性提升
public function __construct(
public string $username,
public string $email,
int $age = 18
) {
$this->age = $age;
}
}

$user = new User("张三", "[email protected]", 25);
echo $user->username; // 张三
?>

析构方法

<?php
class FileHandler {
private $file;

public function __construct($filename) {
$this->file = fopen($filename, "r");
}

public function __destruct() {
if ($this->file) {
fclose($this->file);
}
}
}

$handler = new FileHandler("test.txt");
// 当 $handler 被销毁或脚本结束时,析构方法自动调用
?>

继承

基本继承

<?php
class Animal {
public $name;

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

public function speak() {
return "动物发出声音";
}
}

class Dog extends Animal {
public function speak() {
return $this->name . " 汪汪叫";
}

public function fetch() {
return $this->name . " 去捡球";
}
}

$dog = new Dog("旺财");
echo $dog->speak(); // 旺财 汪汪叫
echo $dog->fetch(); // 旺财 去捡球
?>

parent 关键字

<?php
class Student extends Person {
public $grade;

public function __construct($name, $age, $grade) {
parent::__construct($name, $age); // 调用父类构造方法
$this->grade = $grade;
}

public function greet() {
return parent::greet() . ",我是{$this->grade}年级学生";
}
}
?>

final 关键字

<?php
// final 类不能被继承
final class Singleton {
// ...
}

class BaseClass {
// final 方法不能被重写
final public function getId() {
return $this->id;
}
}
?>

抽象类

<?php
abstract class Shape {
protected $color;

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

// 抽象方法必须由子类实现
abstract public function getArea();

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

class Rectangle extends Shape {
private $width;
private $height;

public function __construct($color, $width, $height) {
parent::__construct($color);
$this->width = $width;
$this->height = $height;
}

public function getArea() {
return $this->width * $this->height;
}
}

$rect = new Rectangle("红色", 10, 5);
echo $rect->getArea(); // 50
?>

接口

定义接口

<?php
interface Flyable {
public function fly(): void;
public function land(): void;
}

interface Swimmable {
public function swim(): void;
}
?>

实现接口

<?php
class Duck implements Flyable, Swimmable {
public function fly(): void {
echo "鸭子在飞";
}

public function land(): void {
echo "鸭子着陆";
}

public function swim(): void {
echo "鸭子在游泳";
}
}
?>

接口继承

<?php
interface Animal {
public function eat(): void;
}

interface Bird extends Animal {
public function layEggs(): void;
}

class Sparrow implements Bird {
public function eat(): void {
echo "麻雀吃虫子";
}

public function layEggs(): void {
echo "麻雀下蛋";
}
}
?>

Trait

定义和使用 Trait

<?php
trait Logger {
protected function log($message) {
echo "[LOG] $message\n";
}
}

trait Timestampable {
public $createdAt;
public $updatedAt;

public function touch() {
$this->updatedAt = new DateTime();
}
}

class User {
use Logger, Timestampable;

public function save() {
$this->touch();
$this->log("用户已保存");
}
}
?>

Trait 冲突解决

<?php
trait A {
public function say() {
echo "A\n";
}
}

trait B {
public function say() {
echo "B\n";
}
}

class MyClass {
use A, B {
B::say insteadof A; // 使用 B 的 say 方法
A::say as sayA; // 给 A 的 say 方法起别名
}
}

$obj = new MyClass();
$obj->say(); // B
$obj->sayA(); // A
?>

修改 Trait 方法可见性

<?php
trait HelloWorld {
public function sayHello() {
echo "Hello World!";
}
}

class MyClass {
use HelloWorld {
sayHello as private; // 改为私有
}

public function greet() {
$this->sayHello(); // 内部可调用
}
}
?>

抽象 Trait 方法

<?php
trait Validator {
// 要求使用类实现此方法
abstract protected function getRules(): array;

public function validate($data) {
$rules = $this->getRules();
// 验证逻辑...
}
}

class UserForm {
use Validator;

protected function getRules(): array {
return [
'name' => 'required',
'email' => 'required|email'
];
}
}
?>

静态成员

<?php
class Counter {
private static $count = 0;

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

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

// 后期静态绑定
public static function create() {
return new static(); // 返回调用类的实例
}
}

class AdvancedCounter extends Counter {}

$c1 = new Counter();
$c2 = new Counter();
$c3 = new AdvancedCounter();

echo Counter::getCount(); // 3

// 后期静态绑定示例
$obj = AdvancedCounter::create();
echo get_class($obj); // AdvancedCounter
?>

常量

<?php
class Math {
// 类常量
const PI = 3.14159;

// PHP 8.3+ 支持类型声明
// const float PI = 3.14159;

public static function area($radius) {
return self::PI * $radius * $radius;
}
}

echo Math::PI; // 3.14159
echo Math::area(5); // 78.53975
?>

魔术方法

__get 和 __set

<?php
class DynamicProperties {
private $data = [];

public function __get($name) {
return $this->data[$name] ?? null;
}

public function __set($name, $value) {
$this->data[$name] = $value;
}

public function __isset($name) {
return isset($this->data[$name]);
}

public function __unset($name) {
unset($this->data[$name]);
}
}

$obj = new DynamicProperties();
$obj->name = "张三"; // 调用 __set
echo $obj->name; // 调用 __get,输出:张三
?>

__call 和 __callStatic

<?php
class MethodOverloading {
public function __call($name, $arguments) {
echo "调用不存在的方法:$name\n";
print_r($arguments);
}

public static function __callStatic($name, $arguments) {
echo "调用不存在的静态方法:$name\n";
print_r($arguments);
}
}

$obj = new MethodOverloading();
$obj->hello("world"); // 调用不存在的方法:hello

MethodOverloading::staticMethod(); // 调用不存在的静态方法:staticMethod
?>

__toString

<?php
class User {
public $name;

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

public function __toString() {
return "User: " . $this->name;
}
}

$user = new User("张三");
echo $user; // User: 张三
?>

__invoke

<?php
class Multiplier {
private $factor;

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

public function __invoke($value) {
return $value * $this->factor;
}
}

$double = new Multiplier(2);
echo $double(5); // 10(像函数一样调用对象)
?>

__clone

<?php
class Person {
public $name;
public $friends;

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

public function __clone() {
// 深拷贝
$this->friends = [];
}
}

$p1 = new Person("张三");
$p1->friends[] = "李四";

$p2 = clone $p1;
$p2->name = "王五";

echo $p1->name; // 张三
echo $p2->name; // 王五
?>

对象比较

<?php
class Point {
public $x;
public $y;

public function __construct($x, $y) {
$this->x = $x;
$this->y = $y;
}
}

$p1 = new Point(1, 2);
$p2 = new Point(1, 2);
$p3 = $p1;

// 比较是否是同一个对象
var_dump($p1 === $p2); // false
var_dump($p1 === $p3); // true

// 比较属性值
var_dump($p1 == $p2); // true
?>

小结

本章我们学习了:

  1. 类与对象:属性、方法、构造函数
  2. 继承:extends、parent、final、abstract
  3. 接口:定义和实现
  4. Trait:代码复用
  5. 静态成员:静态属性和方法
  6. 魔术方法:__get、__set、__call、__toString 等

下一章我们将学习文件操作。