You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何像引用枚举一样引用注册表中的ItemBase对象?

问题描述

我正在开发一个带有物品系统的网页游戏项目,用户背包中的物品实例存储在数据库中,每条记录通过item_base字段关联代码中的物品详细信息,数据库示例如下:

unique_item_idplayer_iditem_base
334534643455ITEM_ONE
385673997212ITEM_TWO

我的ItemBase类定义如下:

class ItemBase {
    public $name;
    public $type;
    public $action;

    public function __construct(string $name, ItemType $type, callable $action) {
        $this->name = $name;
        $this->type = $type->value;
        $this->action = $action();
    }
}

ItemType是标准枚举,返回字符串以避免拼写错误。

我希望将所有ItemBase实例注册在代码中而非单独的数据库表内,以此减少额外查询;同时每个ItemBase的$action字段对应物品使用逻辑,我不想把PHP代码存储在数据库中。创建ItemBase实例的方式如下:

new ItemBase("Item One", ItemType::FOOD, function() {
    // 使用物品时执行的逻辑代码
});

我的核心需求是:能够通过ItemBase::ITEM_ONE这类方式直接引用物品实例,进而调用ItemBase::ITEM_ONE->name等属性。相比数组字符串查找,我更倾向于具备明确类型支持(且IDE能提供代码补全)的方案。由于PHP枚举无法以对象为后盾,是否可以通过注册表类实现?

我曾尝试为每个物品编写静态方法,示例如下:

public static function ITEM_ONE() {
    return new ItemBase("Item One", ItemType::FOOD, function() {
        // 使用物品时执行的逻辑代码
    });
}

这种方式可以通过ItemBase::ITEM_ONE()引用实例,但我不想为每个物品都重复编写静态方法。


最优实现方案

推荐使用静态注册表+魔术方法+IDE类型注释的组合方案,既不用重复编写静态方法,又能获得类型提示和代码补全支持。

方案1:在ItemBase类内集成注册表逻辑

/**
 * @property-read static ItemBase $ITEM_ONE
 * @property-read static ItemBase $ITEM_TWO
 * 后续新增物品时,只需在这里添加对应的@property-read注释即可
 */
class ItemBase {
    public $name;
    public $type;
    public $action;

    // 私有静态注册表,存储所有物品实例
    private static array $registry = [];

    public function __construct(string $name, ItemType $type, callable $action) {
        $this->name = $name;
        $this->type = $type->value;
        // 注意:原代码中$action()会直接执行闭包,若需后续调用逻辑,改为存储闭包本身
        $this->action = $action;
    }

    // 注册物品实例的统一方法
    public static function register(string $key, ItemBase $item): void {
        self::$registry[$key] = $item;
        // 将实例赋值为类的静态属性,实现ItemBase::ITEM_ONE的直接调用
        self::${$key} = $item;
    }

    // 魔术方法,处理静态属性未找到的情况(可选)
    public static function __get(string $key): ?ItemBase {
        return self::$registry[$key] ?? null;
    }
}

// 注册物品实例
ItemBase::register('ITEM_ONE', new ItemBase("Item One", ItemType::FOOD, function() {
    echo "使用食物,恢复生命值";
}));

ItemBase::register('ITEM_TWO', new ItemBase("Item Two", ItemType::WEAPON, function() {
    echo "装备武器,攻击力提升";
}));

方案2:独立的ItemRegistry注册表类

如果不想把注册逻辑和ItemBase耦合,可以单独创建注册表类:

/**
 * @property-read static ItemBase $ITEM_ONE
 * @property-read static ItemBase $ITEM_TWO
 */
class ItemRegistry {
    private static array $items = [];

    public static function register(string $key, ItemBase $item): void {
        self::$items[$key] = $item;
        self::${$key} = $item;
    }

    // 按需获取物品实例的方法
    public static function get(string $key): ?ItemBase {
        return self::$items[$key] ?? null;
    }

    public static function __get(string $key): ?ItemBase {
        return self::$items[$key] ?? null;
    }
}

// 注册物品
ItemRegistry::register('ITEM_ONE', new ItemBase("Item One", ItemType::FOOD, function() {
    // 使用逻辑
}));

// 使用方式
echo ItemRegistry::ITEM_ONE->name;
ItemRegistry::ITEM_ONE->action();

方案优势

  1. 无需为每个物品编写重复的静态方法,仅需调用register一次即可完成注册
  2. 通过@property-read注释让IDE识别静态属性,提供代码补全和类型提示
  3. 所有物品实例集中管理,逻辑清晰且便于维护
  4. 完全避免在数据库中存储PHP代码,所有物品逻辑都在代码层实现

内容的提问来源于stack exchange,提问作者Kohle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:54:57