0

I'm studying OOP PHP and working on a small personal project but I have hard time grasping some concepts. Let's say I have a list of items, each item belongs to subcategory, and each subcategory belongs to category.

So should I make separate classes for category (with methods to list all categories, add new category, delete category), class for subcategories and class for items? Or should I make creating, listing and deleting categories as methods for item class?

Both category and subcategory are very simple and basically consist of ID, Name and parentID (for subcategory).

  • Are the ID fields stored in a database? If not, you may not need them. The pointer to a parent may also be unnecessary. A tree structure doesn't require each node to have a pointer to its parent if you always start at the top (root) node and keep track of the path you took to the current node, so that you always have a context for operations. – itsbruce Nov 11 '13 at 14:16
0

You may be confusing classes, which implement behaviour, and class instances, which can hold data which distinguishes one instance of a class from another.

For the simple situation you describe, you can create one basic category class, which defines the behaviours of

  • Having a name.
  • Having an id.
  • Containing a (possibly empty) list of items.
  • Having a (possibly empty) list of subcategories.

*Having a name" means allowing the name to be read and (optionally) updated. Same for the lists.

You could also give it a parent id but this is not necessary if you always start from your top level category and work down - it depends on how you traverse the structure. For the moment, let's assume you don't need it...

Anyway, having created this class, you then create successive instances of the class, giving each a name, adding items and subcategories etc.

Can you see that the behaviour for each instance is consistent? Each instance may have a unique id, but the act of retrieving or updating that property is the same for all instances.

Now, if you do need your subcategories to know what their parent is, at this point I would consider having two different classes - one for top level categories and another for subcategories. While having one class and leaving the "parent" property empty in top level categories sounds simple, it opens the potential for error, while also burdening top-level categories with surplus fields and methods that they will (or should) never use. Consider these conflicting statements:

  • A top-level category should never have a parent
  • A sub-category always has a parent
  • You make a category a sub-category by giving it a parent
  • You can tell a top-level category because it has no parent

How do you avoid accidentally giving a top level category a parent? Or accidentally removing the parent of a subcategory? How do you detect these errors, after they have happened? The only way to tell a top-level from a sub category is the thing you just broke!

On the other hand, if you have separate classes for top categories and sub-categories, then you can have a top-level category class which simply doesn't have a parent field or any parent-related methods, and a sub-category class which must have these. You never accidentally try to find out the parent of a top-level category because that is something only sub-categories can have.

Of course, now you have the problem of the shared behaviour of top-level and sub-categories. Once answer is to have a simpler category class from which they both inherit. Another is to define a category interface and have both the top and sub category classes implement it. Either way, code which only cares about general category behaviour can treat them both the same.

As for making category management the responsibility of items, I think you have that upside down. Categories need to know something about items, because they contain them. In most situations, items do not need to know anything about categories. Categories are rarely essential properties of items; making your item implementation aware of categories means that if you change your category design, you have to also change your item design. This is called tight coupling, which is generally seen as bad practice. It may seem counter-intuitive at first, but it is generally better to design the different components of a system to know the least amount possible about other components, while exposing as little as possible about their own internal details. This is known as separation of concerns (or "loose coupling").

As a final note, do consider if the id fields are necessary. If these categories are stored in a database, it may be necessary if this part of your code might also change the category names. But do remember that the "Bars" subcategory of "Bike Parts" can be uniquely identified as "/Bike Parts/Bars" and thus completely distinct from "/Venues/Bars". Even if the numerical id is there in the DB, you might not want it in your web code - or not everywhere, anyway. Consider whether you would want external sites linking to http://yoursite.com/Venues/Bars or http://yoursite.com/cat3/cat21.

If you haven't thought as far as persistence yet - or if the category structure would not be stored in a database - I would try implementing this without the ids, first.

1

As categories and subcategories form a tree structure, it will be quite inconvenient to represent that as members of an item. It becomes really convoluted if there is a non-zero chance that some day a subcategory might arise that has subcategories of its own.

What I gather from your description, the only difference between a category and a subcategory is that a category does not have a parent. In that case, I would model category and subcategory as one class (called Category), where the top-level categories are identified by the fact that the parentID field is NULL/empty.
This leads to the advise to use two separate classes, Item and Category. An Item can belong to a Category without knowing if it is a top-level category or a subcategory further down the tree.

  • If the parent id field is truly necessary, it's conceptually better to have separate classes for top level categories (with no parent relationship) and sub-categories (which do), rather than have a null field. PHP supports interfaces, so there's more than one way to do this. – itsbruce Nov 11 '13 at 15:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.