如何像引用枚举一样引用注册表中的ItemBase对象?
问题描述
我正在开发一个带有物品系统的网页游戏项目,用户背包中的物品实例存储在数据库中,每条记录通过item_base字段关联代码中的物品详细信息,数据库示例如下:
| unique_item_id | player_id | item_base |
|---|---|---|
| 3345346 | 43455 | ITEM_ONE |
| 3856739 | 97212 | ITEM_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();
方案优势
- 无需为每个物品编写重复的静态方法,仅需调用
register一次即可完成注册 - 通过
@property-read注释让IDE识别静态属性,提供代码补全和类型提示 - 所有物品实例集中管理,逻辑清晰且便于维护
- 完全避免在数据库中存储PHP代码,所有物品逻辑都在代码层实现
内容的提问来源于stack exchange,提问作者Kohle
相关产品推荐
相关产品推荐

