PHP设计模式是面试中考察开发者代码设计能力的重要内容,面试官通常会通过相关问题判断求职者对面向对象编程思想的理解程度,以及是否具备编写可维护、可扩展代码的能力。下面整理了一些高频出现的PHP设计模式面试问题及对应解答。

问题一:什么是单例模式,PHP中如何实现单例模式
单例模式是一种创建型设计模式,其核心是保证一个类只有一个实例,并且提供一个全局访问点来获取这个实例。它的适用场景包括数据库连接、日志对象、配置对象等需要全局唯一实例的场景。
PHP实现单例模式需要注意几个关键点:构造函数私有化避免外部直接实例化,类内部保存唯一实例的静态属性,提供公共的静态方法返回实例,同时要避免序列化和克隆破坏单例。
<?php
class Database
{
// 保存唯一实例的静态属性
private static $instance = null;
// 私有化构造函数,禁止外部new
private function __construct()
{
// 初始化数据库连接相关逻辑
}
// 禁止克隆
private function __clone() {}
// 禁止序列化
private function __wakeup() {}
// 公共静态方法获取实例
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
// 示例方法:执行查询
public function query($sql)
{
return "执行SQL: " . $sql;
}
}
// 调用方式
$db1 = Database::getInstance();
$db2 = Database::getInstance();
var_dump($db1 === $db2); // 输出bool(true),说明是同一个实例
?>
问题二:工厂模式的分类和适用场景是什么
工厂模式属于创建型设计模式,主要分为简单工厂模式、工厂方法模式和抽象工厂模式三类。
- 简单工厂模式:通过一个工厂类根据传入的参数决定创建哪种产品类的实例,适合产品类型较少且不经常变化的场景。
- 工厂方法模式:定义一个创建对象的接口,让子类决定实例化哪一个类,每个产品对应一个工厂类,适合产品类型可能扩展的场景。
- 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类,适合需要创建多个产品族的场景。
简单工厂模式PHP实现示例
<?php
// 产品接口
interface Product
{
public function getName();
}
// 具体产品A
class ProductA implements Product
{
public function getName()
{
return "产品A";
}
}
// 具体产品B
class ProductB implements Product
{
public function getName()
{
return "产品B";
}
}
// 简单工厂类
class SimpleFactory
{
public static function createProduct($type)
{
switch ($type) {
case 'A':
return new ProductA();
case 'B':
return new ProductB();
default:
throw new Exception("不支持的产品类型");
}
}
}
// 调用示例
$product = SimpleFactory::createProduct('A');
echo $product->getName(); // 输出 产品A
?>
问题三:观察者模式的作用是什么,PHP中如何实现
观察者模式是一种行为型设计模式,定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。它的适用场景包括事件监听、消息通知、订单状态变更后触发多个后续操作等。
PHP中可以通过内置的SplSubject和SplObserver接口实现观察者模式,也可以自定义接口实现。
<?php
// 主题接口
interface Subject
{
public function attach(Observer $observer);
public function detach(Observer $observer);
public function notify();
}
// 观察者接口
interface Observer
{
public function update(Subject $subject);
}
// 具体主题:订单
class Order implements Subject
{
private $observers = [];
private $status;
public function attach(Observer $observer)
{
$this->observers[] = $observer;
}
public function detach(Observer $observer)
{
$key = array_search($observer, $this->observers);
if ($key !== false) {
unset($this->observers[$key]);
}
}
public function notify()
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
public function setStatus($status)
{
$this->status = $status;
$this->notify();
}
public function getStatus()
{
return $this->status;
}
}
// 具体观察者:短信通知
class SmsObserver implements Observer
{
public function update(Subject $subject)
{
echo "发送短信通知:订单状态变更为" . $subject->getStatus() . "<br/>";
}
}
// 具体观察者:邮件通知
class EmailObserver implements Observer
{
public function update(Subject $subject)
{
echo "发送邮件通知:订单状态变更为" . $subject->getStatus() . "<br/>";
}
}
// 调用示例
$order = new Order();
$order->attach(new SmsObserver());
$order->attach(new EmailObserver());
$order->setStatus("已支付");
// 输出:
// 发送短信通知:订单状态变更为已支付
// 发送邮件通知:订单状态变更为已支付
?>
问题四:设计模式的使用原则是什么,为什么不能滥用设计模式
设计模式的使用需要遵循几个核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则、依赖倒置原则。这些原则的核心目标是让代码更易维护、易扩展、易复用。
不能滥用设计模式的原因主要有两点:一是设计模式会增加代码的复杂度,如果项目规模小、需求简单,使用设计模式反而会让代码变得冗余难懂;二是设计模式是为了解决特定场景的问题,不匹配场景强行使用会导致代码设计不合理,反而降低开发效率。
问题五:请说明适配器模式的作用和PHP实现思路
适配器模式属于结构型设计模式,它的作用是将一个类的接口转换成客户端期望的另一个接口,解决接口不兼容的问题,让原本因接口不匹配无法一起工作的类可以协同工作。
实现思路是创建一个适配器类,实现目标接口,同时在适配器内部持有被适配对象的实例,在目标接口的方法中调用被适配对象的方法完成功能适配。
<?php
// 目标接口:期望的支付接口
interface TargetPay
{
public function pay($amount);
}
// 被适配的类:旧的支付宝支付类
class OldAliPay
{
public function oldPay($money)
{
return "旧支付宝支付金额:" . $money;
}
}
// 适配器类
class AliPayAdapter implements TargetPay
{
private $oldAliPay;
public function __construct(OldAliPay $oldAliPay)
{
$this->oldAliPay = $oldAliPay;
}
public function pay($amount)
{
// 调用旧支付类的方法,完成适配
return $this->oldAliPay->oldPay($amount);
}
}
// 调用示例
$oldPay = new OldAliPay();
$adapter = new AliPayAdapter($oldPay);
echo $adapter->pay(100); // 输出 旧支付宝支付金额:100
?>