1.应用场景
熟练掌握PHP面向对象编程, 开发高质量高性能程序. |
2.学习/操作
1. 文档
2. 整理输出PHP 中的多态与面向对象三大特性在 PHP 面向对象编程中,确实有三大核心特性:封装、继承和多态。您提到的"抽象"实际上是封装的一种表现形式。 一、PHP 类的三大特性1. 封装 (Encapsulation)
2. 继承 (Inheritance)
3. 多态 (Polymorphism)
二、PHP 多态行为详解1. 方法重写(子类覆盖父类方法) 2. 接口实现多态 3. 抽象类实现多态 4. 后期静态绑定( |
特性 | PHP | Java | C++ |
编译时多态 | 不支持 | 方法重载 | 函数重载 |
运行时多态 | 支持 | 支持 | 支持 |
多重继承 | 不支持 | 不支持 | 支持 |
接口多继承 | 支持 | 支持 | 不支持 |
总结
PHP 的多态主要通过:
- 方法重写(子类覆盖父类方法)
- 接口实现(不同类实现相同接口)
- 抽象类继承(抽象方法强制子类实现)
- 类型提示(参数类型约束)
多态使代码更加灵活、可扩展和可维护,是面向对象设计中最重要的概念之一。
鸭子类型(Duck Typing)在PHP中的详细解释
鸭子类型是一种动态类型的概念,源自James Whitcomb Riley的名言:"当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。"
核心概念
在编程中,鸭子类型意味着:
- 不关注对象的类型本身
- 只关注对象能否执行特定操作
- 如果一个对象有我们需要的方法和属性,我们就可以像使用目标类型一样使用它
PHP中的鸭子类型特点
- 弱类型系统:PHP不强制要求变量类型
- 运行时检查:方法/属性是否存在在运行时确定
- 接口非必须:即使没有明确实现接口,只要对象有相应方法就能工作
示例说明
示例1:基础鸭子类型
class Duck {
public function quack() {
echo "Quack!\n";
}
public function fly() {
echo "I'm flying!\n";
}
}
class Person {
public function quack() {
echo "I'm pretending to be a duck!\n";
}
public function fly() {
echo "I'm on an airplane!\n";
}
}
function makeItQuack($duckLikeObject) {
$duckLikeObject->quack();
}
makeItQuack(new Duck()); // 输出: Quack!
makeItQuack(new Person()); // 输出: I'm pretending to be a duck!
分析:
makeItQuack
函数不检查参数类型
- 只要对象有
quack()
方法就能工作
Person
不是鸭子,但可以"像鸭子一样叫"
示例2:实际应用场景
class FileLogger {
public function write($message) {
file_put_contents('app.log', $message, FILE_APPEND);
}
}
class DatabaseLogger {
public function write($message) {
DB::insert('logs', ['message' => $message]);
}
}
function logMessage($logger, $message) {
$logger->write($message);
}
logMessage(new FileLogger(), "Error occurred"); // 写入文件
logMessage(new DatabaseLogger(), "Error occurred"); // 写入数据库
优势:
- 不需要共同接口
- 不需要继承关系
- 只要都有
write()
方法就能工作
示例3:与接口的对比
// 接口方式
interface LoggerInterface {
public function write($message);
}
class FileLogger implements LoggerInterface { /*...*/ }
class DBLogger implements LoggerInterface { /*...*/ }
// 鸭子类型方式
// 不需要实现接口,只要有write方法就行
class EmailLogger {
public function write($message) {
mail('admin@test.com', 'Error', $message);
}
}
function logError($logger, $message) {
$logger->write($message);
}
logError(new EmailLogger(), "Something broke"); // 正常工作
鸭子类型的优缺点
优点
- 灵活性:不需要严格的类型层次结构
- 简洁性:减少接口和抽象类的使用
- 快速原型:易于快速开发和测试
- 动态性:运行时决定行为
缺点
- 安全性:缺乏编译时类型检查
- 可读性:难以从代码直接看出预期接口
- 维护性:修改时可能破坏依赖该对象的代码
- IDE支持:自动完成和重构工具支持较差
PHP中的最佳实践
- 文档注释:用
@method
和@property
标注预期行为
/**
* @method void quack() 应该实现鸭子叫声
* @method void fly() 应该实现飞行能力
*/
function makeItQuack($duckLikeObject) {
$duckLikeObject->quack();
}
- 防御性编程:使用检查
function makeItQuack($duckLikeObject) {
if (!method_exists($duckLikeObject, 'quack')) {
throw new InvalidArgumentException('对象必须实现quack方法');
}
$duckLikeObject->quack();
}
- 渐进式类型:PHP 7+可用类型提示但保持灵活性
function makeItQuack(object $duckLikeObject) {
if (!method_exists($duckLikeObject, 'quack')) {
throw new InvalidArgumentException('对象必须实现quack方法');
}
$duckLikeObject->quack();
}
与接口的对比
特性 | 鸭子类型 | 接口 |
类型安全 | 运行时检查 | 编译时检查 |
耦合度 | 低 | 高 |
明确性 | 隐式约定 | 显式契约 |
灵活性 | 高 | 中 |
重构难度 | 困难 | 容易 |
IDE支持 | 有限 | 良好 |
实际框架中的应用
Laravel 集合的鸭子类型
// 任何实现了可遍历方法的对象都能被collect()包装
$collection = collect(new ArrayObject([1, 2, 3]));
// 因为ArrayObject实现了所需的遍历方法
Mock对象测试
// 创建测试用的鸭子类型对象
$mockUser = new class {
public function getId() { return 1; }
public function getName() { return 'Test'; }
};
// 即使没有实现User接口也能工作
$userService->process($mockUser);
总结
鸭子类型在PHP中表现为:
- 关注行为而非类型
- 动态检查方法/属性是否存在
- 提高代码灵活性但降低安全性
- 适合快速原型和小型项目
- 大型项目中建议结合接口使用
理解鸭子类型有助于更好地利用PHP的动态特性,但也需要注意其潜在风险。
在团队开发或大型项目中,通常建议使用接口来获得更好的可维护性,而在脚本或快速开发中可以充分利用鸭子类型的灵活性。
后续整理补充
...
3.问题/补充
1. new self() 和 new static() 的区别
|
后续补充
...