PHP 中 Class 的使用说明
文章目录
- PHP 中 Class 的使用说明
- 1. 类(Class)的基础概念
- 2. 类的定义与实例化
- 2.1 定义类
- 2.2 实例化类(创建对象)
- 2.3 构造函数
- 2.4 析构函数
- 3. 属性(Properties)
- 3.1 属性的类型
- 3.2 属性的访问控制
- 3.3 属性的默认值
- 3.4 静态属性
- 3.5 只读属性(PHP 8.1+)
- 4. 方法(Methods)
- 4.1 方法的定义和调用
- 4.2 方法的访问控制
- 4.3 静态方法
- 4.4 抽象方法
- 4.5 魔术方法
- 5. 继承(Inheritance)
- 5.1 基本继承
- 5.2 调用父类的方法
- 5.3 多继承的替代方案(Trait)
- 6. 多态(Polymorphism)
- 7. 抽象类与接口
- 7.1 抽象类
- 7.2 接口
- 7.3 抽象类与接口的区别
- 8. 面向对象设计原则
- 8.1 单一职责原则(SRP)
- 8.2 开闭原则(OCP)
- 8.3 里氏替换原则(LSP)
- 8.4 接口隔离原则(ISP)
- 8.5 依赖倒置原则(DIP)
- 9. 高级类特性
- 9.1 类的自动加载
- 9.2 命名空间
- 9.3 反射
- 9.4 对象序列化
- 10. 实际应用示例
- 10.1 基础的 MVC 结构
- 10.2 单例模式
- 10.3 工厂模式
- 11. 类的最佳实践
- 11.1 命名规范
- 11.2 代码组织
- 11.3 可维护性
- 11.4 安全性
- 12. 总结
PHP 中 Class 的使用说明
1. 类(Class)的基础概念
在 PHP 中,类是面向对象编程(OOP)的核心概念,它是一种用于创建对象的蓝图或模板。类定义了对象的属性(数据)和方法(行为),而对象则是类的实例化。
类的主要特性包括:
- 封装:将数据和方法组合在一个单元中
- 继承:允许一个类基于另一个类构建
- 多态:允许不同的类实现相同的方法但有不同的行为
- 抽象:允许定义接口和抽象类
2. 类的定义与实例化
2.1 定义类
使用 class
关键字定义一个类:
<?php
// 定义一个简单的 Person 类
class Person {// 属性(成员变量)public $name;public $age;// 方法(成员函数)public function sayHello() {echo "Hello, my name is {$this->name}.";}
}
?>
2.2 实例化类(创建对象)
使用 new
关键字创建类的实例:
<?php
// 创建 Person 类的实例
$person = new Person();// 访问对象的属性并赋值
$person->name = "张三";
$person->age = 30;// 调用对象的方法
$person->sayHello(); // 输出: Hello, my name is 张三.
?>
2.3 构造函数
构造函数是一种特殊的方法,在创建对象时自动调用,用于初始化对象的属性:
<?php
class Person {public $name;public $age;// 构造函数public function __construct($name, $age) {$this->name = $name;$this->age = $age;}public function sayHello() {echo "Hello, my name is {$this->name}.";}
}// 创建对象时直接传递参数
$person = new Person("张三", 30);
$person->sayHello(); // 输出: Hello, my name is 张三.
?>
2.4 析构函数
析构函数在对象被销毁时自动调用,通常用于清理资源:
<?php
class FileHandler {private $file;public function __construct($filename) {$this->file = fopen($filename, "r");}// 析构函数public function __destruct() {if ($this->file) {fclose($this->file);echo "文件已关闭";}}
}$handler = new FileHandler("example.txt");
// 当 $handler 不再被引用或脚本结束时,析构函数会自动调用
?>
3. 属性(Properties)
属性是类中用于存储数据的变量,也称为成员变量。
3.1 属性的类型
PHP 7.4+ 支持属性类型声明:
<?php
class Person {// 基本类型声明public string $name;public int $age;public float $height;public bool $isStudent;// 可为空类型(PHP 8.0+)public ?string $email;// 类类型声明public DateTime $registrationDate;
}
?>
3.2 属性的访问控制
PHP 提供了三种访问控制修饰符:
<?php
class Person {// 公共属性:可以在任何地方访问public $name;// 受保护属性:只能在类内部或子类中访问protected $email;// 私有属性:只能在定义它的类内部访问private $phone;// ...其他代码
}
?>
3.3 属性的默认值
可以为属性设置默认值:
<?php
class Person {public string $name = "Guest";public int $age = 0;public array $hobbies = [];public ?string $email = null;
}
?>
3.4 静态属性
静态属性属于类本身,而不是类的实例:
<?php
class Counter {// 静态属性public static int $count = 0;public function __construct() {self::$count++; // 使用 self:: 访问静态属性}
}$c1 = new Counter();
$c2 = new Counter();echo Counter::$count; // 输出: 2
?>
3.5 只读属性(PHP 8.1+)
只读属性只能在初始化时赋值一次:
<?php
class User {public readonly int $id;public function __construct(int $id) {$this->id = $id; // 只能在构造函数中赋值}
}$user = new User(123);
// $user->id = 456; // 错误:不能修改只读属性
?>
4. 方法(Methods)
方法是类中定义的函数,用于执行特定操作。
4.1 方法的定义和调用
<?php
class Calculator {// 方法定义public function add(int $a, int $b): int {return $a + $b;}
}$calc = new Calculator();
$result = $calc->add(5, 3); // 调用方法echo $result; // 输出: 8
?>
4.2 方法的访问控制
与属性一样,方法也有三种访问控制修饰符:
<?php
class Person {private $name;// 公共方法public function setName(string $name): void {$this->name = $name;}// 受保护方法protected function validateName(string $name): bool {return strlen($name) > 0;}// 私有方法private function formatName(string $name): string {return ucfirst($name);}
}
?>
4.3 静态方法
静态方法属于类本身,不依赖于类的实例:
<?php
class Math {// 静态方法public static function square(int $num): int {return $num * $num;}
}// 直接通过类名调用静态方法
$result = Math::square(5);
echo $result; // 输出: 25
?>
4.4 抽象方法
抽象方法是在抽象类中声明但不实现的方法,子类必须实现它:
<?php
abstract class Shape {// 抽象方法abstract public function calculateArea(): float;
}class Rectangle extends Shape {private $width;private $height;public function __construct(float $width, float $height) {$this->width = $width;$this->height = $height;}// 实现抽象方法public function calculateArea(): float {return $this->width * $this->height;}
}
?>
4.5 魔术方法
PHP 提供了一系列魔术方法,这些方法以双下划线 __
开头,在特定情况下自动调用:
<?php
class Person {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]);}// 方法调用魔术方法public function __call($name, $arguments) {echo "调用了方法 $name ,参数:" . implode(', ', $arguments);}// 静态方法调用魔术方法public static function __callStatic($name, $arguments) {echo "调用了静态方法 $name ,参数:" . implode(', ', $arguments);}// 字符串转换魔术方法public function __toString() {return "Person object";}
}
?>
5. 继承(Inheritance)
继承允许一个类(子类)基于另一个类(父类)构建,从而重用代码:
5.1 基本继承
<?php
// 父类
class Animal {protected $name;public function __construct($name) {$this->name = $name;}public function getName() {return $this->name;}public function makeSound() {echo "Some generic sound";}
}// 子类继承父类
class Dog extends Animal {// 重写父类的方法public function makeSound() {echo "Woof! Woof!";}// 子类特有的方法public function fetch() {echo "{$this->name} is fetching the ball";}
}// 创建子类的实例
$dog = new Dog("Rex");
echo $dog->getName(); // 输出: Rex
$dog->makeSound(); // 输出: Woof! Woof!
$dog->fetch(); // 输出: Rex is fetching the ball
?>
5.2 调用父类的方法
使用 parent::
关键字调用父类的方法:
<?php
class ParentClass {public function sayHello() {echo "Hello from Parent";}
}class ChildClass extends ParentClass {public function sayHello() {// 调用父类的方法parent::sayHello();echo "Hello from Child";}
}$child = new ChildClass();
$child->sayHello(); // 输出: Hello from ParentHello from Child
?>
5.3 多继承的替代方案(Trait)
PHP 不支持多继承,但可以使用 Trait 实现类似功能:
<?php
// 定义一个 Traittrait Logger {public function log($message) {echo "[LOG] $message\n";}
}// 定义另一个 Traittrait Database {public function connect() {echo "Connected to database\n";}
}// 使用多个 Trait
class User {use Logger, Database;public function register() {$this->connect();$this->log("User registered");}
}$user = new User();
$user->register(); // 输出: Connected to database [LOG] User registered
?>
6. 多态(Polymorphism)
多态允许不同的类实现相同的接口或继承自同一个父类,但有不同的行为:
<?php
// 定义一个接口
interface Shape {public function calculateArea();
}// 实现接口的类
class Circle implements Shape {private $radius;public function __construct($radius) {$this->radius = $radius;}public function calculateArea() {return pi() * pow($this->radius, 2);}
}class Rectangle implements Shape {private $width;private $height;public function __construct($width, $height) {$this->width = $width;$this->height = $height;}public function calculateArea() {return $this->width * $this->height;}
}// 多态的使用
function printArea(Shape $shape) {echo "Area: " . $shape->calculateArea() . "\n";
}$circle = new Circle(5);
$rectangle = new Rectangle(4, 6);printArea($circle); // 输出: Area: 78.539816339745
printArea($rectangle); // 输出: Area: 24
?>
7. 抽象类与接口
7.1 抽象类
抽象类是不能直接实例化的类,可以包含抽象方法和普通方法:
<?php
// 定义抽象类
abstract class Vehicle {protected $brand;public function __construct($brand) {$this->brand = $brand;}// 普通方法public function getBrand() {return $this->brand;}// 抽象方法abstract public function startEngine();
}// 继承抽象类并实现抽象方法
class Car extends Vehicle {public function startEngine() {echo "{$this->brand} car engine started";}
}// 不能直接实例化抽象类
// $vehicle = new Vehicle("Toyota"); // 错误$car = new Car("Toyota");
$car->startEngine(); // 输出: Toyota car engine started
?>
7.2 接口
接口定义了一个类应该实现的方法,但不提供方法的具体实现:
<?php
// 定义接口
interface Logger {public function logInfo($message);public function logError($message);public function logWarning($message);
}// 实现接口
class FileLogger implements Logger {private $logFile;public function __construct($logFile) {$this->logFile = $logFile;}public function logInfo($message) {$this->writeLog("INFO", $message);}public function logError($message) {$this->writeLog("ERROR", $message);}public function logWarning($message) {$this->writeLog("WARNING", $message);}private function writeLog($level, $message) {$timestamp = date("Y-m-d H:i:s");$logEntry = "[$timestamp] [$level] $message\n";file_put_contents($this->logFile, $logEntry, FILE_APPEND);}
}// 使用实现了接口的类
$logger = new FileLogger("app.log");
$logger->logInfo("Application started");
$logger->logError("Database connection failed");
?>
7.3 抽象类与接口的区别
特性 | 抽象类 | 接口 |
---|---|---|
方法实现 | 可以包含已实现的方法 | 只能包含方法声明,不能实现 |
属性 | 可以包含各种访问级别的属性 | 只能包含公共静态常量 |
继承 | 一个类只能继承一个抽象类 | 一个类可以实现多个接口 |
构造函数 | 可以有构造函数 | 不能有构造函数 |
访问控制 | 可以使用各种访问修饰符 | 方法默认为公共,不能使用其他修饰符 |
8. 面向对象设计原则
8.1 单一职责原则(SRP)
一个类应该只有一个责任:
<?php
// 好的设计:User 类只负责用户数据和行为
class User {private $id;private $name;private $email;// 只包含与用户相关的方法public function getName() { return $this->name; }public function setName($name) { $this->name = $name; }// ...
}// 好的设计:UserRepository 类只负责数据库操作
class UserRepository {public function save(User $user) { /* 保存用户到数据库 */ }public function findById($id) { /* 从数据库查找用户 */ }// ...
}
?>
8.2 开闭原则(OCP)
软件实体应该对扩展开放,对修改关闭:
<?php
// 好的设计:使用接口和继承实现开闭原则
interface PaymentMethod {public function pay($amount);
}class CreditCardPayment implements PaymentMethod {public function pay($amount) { /* 信用卡支付逻辑 */ }
}class PayPalPayment implements PaymentMethod {public function pay($amount) { /* PayPal支付逻辑 */ }
}// PaymentProcessor 对扩展开放,对修改关闭
class PaymentProcessor {public function processPayment(PaymentMethod $method, $amount) {return $method->pay($amount);}
}// 新增支付方式不需要修改 PaymentProcessor
class BitcoinPayment implements PaymentMethod {public function pay($amount) { /* 比特币支付逻辑 */ }
}
?>
8.3 里氏替换原则(LSP)
子类应该能够替换其父类:
<?php
class Rectangle {protected $width;protected $height;public function setWidth($width) { $this->width = $width; }public function setHeight($height) { $this->height = $height; }public function getArea() { return $this->width * $this->height; }
}// 正方形是一种特殊的矩形,但这个实现违反了里氏替换原则
class Square extends Rectangle {public function setWidth($width) {$this->width = $width;$this->height = $width;}public function setHeight($height) {$this->width = $height;$this->height = $height;}
}// 更好的设计:使用组合而非继承
interface Shape {public function getArea();
}class Rectangle implements Shape {// ...
}class Square implements Shape {// ...
}
?>
8.4 接口隔离原则(ISP)
不应该强迫客户端依赖于它们不使用的方法:
<?php
// 不好的设计:一个大而全的接口
interface Worker {public function work();public function eat();public function sleep();
}// 好的设计:将接口拆分为更小、更具体的接口
interface Workable {public function work();
}interface Eatable {public function eat();
}interface Sleepable {public function sleep();
}// 客户端可以只实现需要的接口
class HumanWorker implements Workable, Eatable, Sleepable {// 实现所有方法
}class RobotWorker implements Workable {// 只需要实现 work() 方法public function work() { /* 工作逻辑 */ }
}
?>
8.5 依赖倒置原则(DIP)
高层模块不应该依赖于低层模块,两者都应该依赖于抽象:
<?php
// 不好的设计:高层模块直接依赖低层模块
class UserService {private $mysqlRepository; // 直接依赖具体类public function __construct() {$this->mysqlRepository = new MySQLUserRepository();}
}// 好的设计:依赖于抽象接口
interface UserRepository {public function findById($id);public function save(User $user);
}class MySQLUserRepository implements UserRepository {// 实现接口方法
}class MongoDBUserRepository implements UserRepository {// 实现接口方法
}class UserService {private $repository; // 依赖于抽象接口// 通过构造函数注入依赖public function __construct(UserRepository $repository) {$this->repository = $repository;}
}
?>
9. 高级类特性
9.1 类的自动加载
使用 spl_autoload_register() 实现类的自动加载:
<?php
// 自动加载函数
function my_autoloader($class) {// 将命名空间分隔符转换为目录分隔符$path = str_replace('\\', DIRECTORY_SEPARATOR, $class);// 加载对应的类文件require_once __DIR__ . '/classes/' . $path . '.php';
}// 注册自动加载函数
spl_autoload_register('my_autoloader');// 现在可以直接使用类,不需要手动引入
$user = new App\Models\User();
?>
9.2 命名空间
命名空间可以避免类名冲突:
<?php
// 定义命名空间
namespace App\Models;class User {// 类定义
}// 在其他文件中使用命名空间
namespace App\Controllers;// 使用 use 语句引入类
use App\Models\User;class UserController {public function index() {$user = new User();// ...}
}// 也可以使用完全限定名称
$user = new \App\Models\User();
?>
9.3 反射
反射 API 允许在运行时检查类、接口、方法和属性:
<?php
class Person {public $name;private $age;public function __construct($name, $age) {$this->name = $name;$this->age = $age;}public function sayHello() {echo "Hello, my name is {$this->name}.";}
}// 创建反射类
$reflection = new ReflectionClass('Person');// 获取类的信息
echo "类名: " . $reflection->getName() . "\n";echo "公共方法: " . "\n";
foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {echo " - " . $method->getName() . "\n";
}echo "属性: " . "\n";
foreach ($reflection->getProperties() as $property) {echo " - " . $property->getName() . "\n";
}// 创建实例
$person = $reflection->newInstanceArgs(["张三", 30]);
$person->sayHello(); // 输出: Hello, my name is 张三.
?>
9.4 对象序列化
序列化将对象转换为字符串,反序列化则将字符串恢复为对象:
<?php
class Person {public $name;public $age;public function __construct($name, $age) {$this->name = $name;$this->age = $age;}public function sayHello() {echo "Hello, my name is {$this->name}.";}
}// 创建对象
$person = new Person("张三", 30);// 序列化对象
$serialized = serialize($person);
echo $serialized; // 输出序列化的字符串// 将序列化的字符串存储到文件
file_put_contents("person.txt", $serialized);// 从文件读取序列化的字符串
$serialized = file_get_contents("person.txt");// 反序列化对象
$unserialized = unserialize($serialized);
$unserialized->sayHello(); // 输出: Hello, my name is 张三.
?>
10. 实际应用示例
10.1 基础的 MVC 结构
<?php
// 模型(Model)
class UserModel {private $db;public function __construct($db) {$this->db = $db;}public function getUserById($id) {// 从数据库获取用户}public function saveUser($userData) {// 保存用户到数据库}
}// 视图(View)
class UserView {public function renderUserProfile($user) {// 渲染用户资料页面echo "<h1>{$user['name']}</h1>";echo "<p>Email: {$user['email']}</p>";}public function renderUserForm() {// 渲染用户表单echo "<form>...</form>";}
}// 控制器(Controller)
class UserController {private $model;private $view;public function __construct($model, $view) {$this->model = $model;$this->view = $view;}public function showProfile($id) {$user = $this->model->getUserById($id);$this->view->renderUserProfile($user);}public function showEditForm($id) {$user = $this->model->getUserById($id);$this->view->renderUserForm($user);}public function updateUser($id, $userData) {$this->model->saveUser($userData);// 重定向到用户资料页}
}// 使用示例
$db = new PDO("mysql:host=localhost;dbname=test", "root", "password");
$userModel = new UserModel($db);
$userView = new UserView();
$userController = new UserController($userModel, $userView);// 路由决定调用哪个控制器方法
$userController->showProfile(1);
?>
10.2 单例模式
<?php
// 单例模式确保一个类只有一个实例
class Database {// 保存单例实例的静态属性private static $instance = null;// 数据库连接private $connection;// 私有构造函数防止外部实例化private function __construct() {$this->connection = new PDO("mysql:host=localhost;dbname=test", "root", "password");}// 防止克隆对象private function __clone() {}// 防止反序列化private function __wakeup() {}// 获取单例实例的公共静态方法public static function getInstance() {if (self::$instance === null) {self::$instance = new self();}return self::$instance;}// 获取数据库连接public function getConnection() {return $this->connection;}
}// 使用单例
$db1 = Database::getInstance();
$db2 = Database::getInstance();// $db1 和 $db2 是同一个实例
var_dump($db1 === $db2); // 输出: bool(true)// 使用连接
$conn = $db1->getConnection();
?>
10.3 工厂模式
<?php
// 产品接口
interface Vehicle {public function drive();
}// 具体产品
class Car implements Vehicle {public function drive() {echo "Driving a car";}
}class Motorcycle implements Vehicle {public function drive() {echo "Riding a motorcycle";}
}// 工厂类
class VehicleFactory {// 工厂方法public static function createVehicle($type) {switch ($type) {case 'car':return new Car();case 'motorcycle':return new Motorcycle();default:throw new Exception("Unsupported vehicle type");}}
}// 使用工厂创建对象
$car = VehicleFactory::createVehicle('car');
$car->drive(); // 输出: Driving a car$motorcycle = VehicleFactory::createVehicle('motorcycle');
$motorcycle->drive(); // 输出: Riding a motorcycle
?>
11. 类的最佳实践
11.1 命名规范
- 类名使用大驼峰命名法(PascalCase):
User
,DatabaseConnection
- 方法名和属性名使用小驼峰命名法(camelCase):
getUserById()
,$firstName
- 常量名使用全大写加下划线:
MAX_CONNECTIONS
,DEFAULT_TIMEOUT
- 私有属性和方法可以使用下划线前缀:
$_privateVar
,_privateMethod()
11.2 代码组织
- 将每个类放在单独的文件中
- 使用命名空间组织类
- 遵循 PSR 标准(特别是 PSR-1、PSR-4)
- 使用自动加载而非手动引入
11.3 可维护性
- 保持类的职责单一
- 编写清晰的注释和文档
- 使用类型声明提高代码的可靠性
- 避免深度嵌套的继承层次
- 优先使用组合而非继承
- 合理使用设计模式
11.4 安全性
- 不要在类中硬编码敏感信息
- 使用访问控制修饰符保护类的内部状态
- 对输入进行验证和过滤
- 避免魔术方法的滥用
- 注意序列化安全
12. 总结
PHP 的类和面向对象编程提供了强大的工具,使代码更有组织性、可重用性和可维护性。通过合理使用类、继承、接口、抽象类和设计模式,您可以构建复杂且灵活的应用程序。
本指南涵盖了 PHP 类的核心概念和高级特性,包括类的定义与实例化、属性与方法、访问控制、继承、多态、抽象类与接口、设计原则和实际应用示例。通过不断学习和实践,您可以进一步提升您的面向对象编程技能。