I’m working on a web game project which has the concept of items.
Individual instances of items, which a user could have in their inventory, are stored in the database. Each of those rows has a column called item_base
which is used in the code to get details about the item. Example:
unique_item_id | player_id | item_base |
---|---|---|
3345346 | 43455 | ITEM_ONE |
3856739 | 97212 | ITEM_TWO |
My ItemBase
class:
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();
}
}
The ItemType
enum is just a standard enum that returns a string to prevent typos.
I’m looking to "register" all of my item bases in the codebase rather than its own table in the database since I want to prevent additional queries. Each item base also has a function ($action
) to determine which code should be executed when the item is used, and I’m avoiding putting PHP directly into the database.
Creating a new item base would be like this:
new ItemBase("Item One", ItemType::FOOD, function() {
//Code to execute when the function is called
});
My goal is to be able to reference item bases with something like ItemBase::ITEM_ONE
. Then I can use ItemBase::ITEM_ONE->name
or the other variables passed through the construct.
What is the best way to approach this? Being able to have the defined type (which IDEs also support type completion on) is preferred over using an $array[‘string’] lookup. Since enums can’t be backed by an object, can I do something with a registry type class?
I’ve tried creating a class with all of my ItemBases in them and then registering each one similar to this:
public static function ITEM_ONE() {
return new ItemBase("Item One", ItemType::FOOD, function() {
//Code to execute when the function is called
});
This then allows me to use ItemBase::ITEM_ONE()
, but I’m looking for a method that doesn’t require a function for each item base in the game.
2
Answers
You can use a regsitry class and the
__callStatic
magic methodYou could optionally define the registry stuff on the
ItemBase
class instead of making a separateItemStore
class.Why not use the name of the enum entry as key in a lookup array? It is a distinct value, so perfectly usable as key in a map.
Output:
Note the parentheses around the lookup and property access for action. The parentheses are necessary because the function call () has higher precedence than the property access with ->.
Or the same with a (type safe) registry class: