PHP项目蝇量与共享对象

wen PHP项目 1

本文目录导读:

PHP项目蝇量与共享对象

  1. 🪶 1. 蝇量模式 (Flyweight Pattern)
  2. 📦 2. 共享对象 (Shared Object)
  3. 🆚 对比:蝇量模式 vs 共享对象
  4. 🧠 实战建议

在PHP项目中,“蝇量模式”(Flyweight Pattern)和“共享对象”(Shared Object)是两种不同的概念,但它们在解决内存和性能问题上有关联。


🪶 1. 蝇量模式 (Flyweight Pattern)

核心思想

通过共享相同状态的对象来减少内存使用,适用于系统中存在大量细粒度对象、且这些对象可以拆分为内部状态(共享)和外部状态(不共享)的场景。

在 PHP 中的实现

// 1. 定义蝇量接口
interface CharacterFlyweight {
    public function render(string $externalState): string;
}
// 2. 共享对象(内部状态:字体样式)
class ConcreteCharacter implements CharacterFlyweight {
    private string $fontFamily;
    private int $fontSize;
    public function __construct(string $fontFamily, int $fontSize) {
        $this->fontFamily = $fontFamily;
        $this->fontSize = $fontSize;
    }
    public function render(string $character): string {
        return sprintf(
            "<span style='font-family:%s; font-size:%dpx'>%s</span>",
            $this->fontFamily,
            $this->fontSize,
            $character
        );
    }
}
// 3. 工厂(管理共享对象池)
class CharacterFactory {
    private array $pool = [];
    public function getCharacter(string $fontFamily, int $fontSize): CharacterFlyweight {
        $key = md5("{$fontFamily}_{$fontSize}");
        if (!isset($this->pool[$key])) {
            $this->pool[$key] = new ConcreteCharacter($fontFamily, $fontSize);
        }
        return $this->pool[$key];
    }
}
// 4. 客户端使用
$factory = new CharacterFactory();
$characters = ['A', 'B', 'C', 'A', 'B', 'A'];
// 即使渲染多个字符,字体对象只生成 3 个
$renderResults = [];
foreach ($characters as $char) {
    $flyweight = $factory->getCharacter('Arial', 12); // 共享同一个字体对象
    $renderResults[] = $flyweight->render($char);
}

📦 2. 共享对象 (Shared Object)

在 PHP 中,“共享对象”可以指不同层面的概念:

a. 对象池模式(Object Pool)

与蝇量模式不同,对象池的核心是复用创建成本高的对象(如数据库连接、大对象)。

class ConnectionPool {
    private array $available = [];
    private array $inUse = [];
    public function getConnection(): PDO {
        if (empty($this->available)) {
            // 创建新连接(成本高)
            $conn = new PDO("mysql:host=localhost;dbname=test", "user", "pass");
        } else {
            $conn = array_pop($this->available);
        }
        $this->inUse[spl_object_id($conn)] = $conn;
        return $conn;
    }
    public function release(PDO $conn): void {
        $id = spl_object_id($conn);
        if (isset($this->inUse[$id])) {
            unset($this->inUse[$id]);
            $this->available[] = $conn;
        }
    }
}

b. 共享变量/状态(多进程/多线程)

PHP-FPM 模式下,不同请求之间无法直接共享对象,但可以通过:

  • APCu / Redis / Memcached 存储序列化对象
  • Swoole 协程 共享内存
  • 共享扩展(如 shmop 操作共享内存块)
// APCu 示例
apcu_store('shared_config', ['db_host' => 'localhost']);
$config = apcu_fetch('shared_config');

c. 单例模式(进程内共享)

确保一个类只有一个实例,在当前 PHP 进程内共享:

class DBConnection {
    private static ?self $instance = null;
    private PDO $pdo;
    private function __construct() { /* 初始化连接 */ }
    public static function getInstance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}

🆚 对比:蝇量模式 vs 共享对象

特性 蝇量模式 共享对象(对象池)
目的 减少内存(对象数量) 复用创建成本
核心机制 将对象拆分为内部/外部状态 预创建 + 循环使用
适用场景 大量相似对象(如字符、粒子) 昂贵资源(连接、线程)
对象属性 不可变内部状态(共享) 可被重置
生命周期 长期存在(池化管理) 受池容量限制
PHP 典型例子 文本渲染、游戏粒子系统 数据库连接池

🧠 实战建议

  1. 使用蝇量模式的前提:对象数量非常大(>1000)且对象可拆分为共享/非共享部分。
  2. 对象池的应用:在数据库、HTTP客户端、大型计算结果缓存中非常有效。
  3. 注意线程安全:Swoole 协程环境下共享对象需加锁。
  4. 性能权衡:共享对象节省了创建时间但增加了管理开销,需要根据业务场景选择合适的实现。

📚 代码示例链接(GitHub)

需要我针对某个具体场景给出更详细的实现吗?

抱歉,评论功能暂时关闭!