Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 9178529
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 17, 20262026-06-17T17:34:24+00:00 2026-06-17T17:34:24+00:00

I have a base user class which is responsible for manipulating the basic user

  • 0

I have a base user class which is responsible for manipulating the basic user information: name, age, location, etc. I want to extend my system with the groups functionality and later with projects and meetings. For example:

class User
{
    public function getName() {
        ...
    }

    public function getAge() {
        ...
    }
}

And then extend it with groups functionality:

class GroupableUser extends User
{
    public function join($groupId) {
        ...
    }

    public function leave($groupId) {

    }

    public function requestGroupInvitation($groupId) {
        ...
    }

    public function acceptGroupInvitation($groupId) {
        ...
    }
}

The name GroupableUser seems weird to me, however it does’t make sense to add join and leave methods to Group class, because its user that joins and leaves a group, not the other way around.

And later I would have classes like UserThatCanHaveProjects and UserThatCanParticipateInMeetings.
How to name these classes?

And how do you typically deal with these situations?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-17T17:34:25+00:00Added an answer on June 17, 2026 at 5:34 pm

    The capability to participate in groups/meetings and have projects is something that a user might be able to do, but it’s not something that defines what a user is. This is a pretty clear sign that modelling these options with additional classes is not a good design choice.

    Static approach #1: interfaces

    In a statically typed language a simplistic implementation would look something like

    interface IGrouppableUser {
         public function join(...);
    }
    
    class GroupableUser implements IGrouppableUser {
         public function join(...) { /* implementation */ }
    }
    

    And the consumers of grouppable users would accept IGrouppableUser, allowing you to craft as many classes as necessary. You can also do this in PHP, but as mentioned earlier it’s probably not a good design no matter what the language.

    As a footnote, I should add that with the addition of traits to the language starting from PHP 5.4 the above scenario can be implemented a bit more conveniently (classes can use a trait instead of implementing an interface, which means you don’t need to copy/paste the implementation of join all around the code base). But conceptually it’s the exact same approach.

    The main disadvantage of this approach is that it does not scale. It might be OK if you only need two or three types of users.

    Static approach #2: “not supported” exceptions

    If most of the users are grouppable and can have projects then it doesn’t make much sense to create a hellish hierarchy of classes; you can just add the necessary members to class User, making it a fat interface:

    class GroupableUser implements IGrouppableUser {
         private $isGrouppable = true; // default, can be changed at runtime
    
         public function join(...) {
             if (!$this->isGrouppable) throw new Exception("User is not grouppable!");
    
             // real implementation
         }
    }
    

    The main disadvantage of this approach is that it makes the class User appear to unconditionally support a wide range of operations when in fact it does not and as a result can make coding tedious and error-prone (lots of try/catch). It might be OK if the vast majority of users support the vast majority of operations.

    Dynamic approach #1: behaviors

    It would be much better to conditionally allow User instances to participate in these operations. This means that you need to be able to dynamically attach “behaviors” to User objects, which is fortunately quite easy to do in a dynamically typed language.

    I suggest looking up a “behaviors” implementation from an established open-source project, but here’s a quick and dirty example:

    Behavior base class and sample implementation

    abstract class Behavior {
        public function provides($name) {
            return method_exists($this, $name);
        }
    
        public function invoke($target, $name, $arguments) {
            array_unshift($arguments, $target);
            return call_user_func_array(array($this, $name), $arguments);
        }
    }
    
    class GrouppableBehavior extends Behavior {
        public function join(User $user, $groupName) {
            echo "The user has joined group $groupName.";
        }
    }
    

    Composable (can use behaviors) base class and User implementation

    class Composable {
        private $behaviors = array();
    
        public function __call($name, $arguments) {
            foreach ($this->behaviors as $behavior) {
                if ($behavior->provides($name)) {
                    return $behavior->invoke($this, $name, $arguments);
                }
            }
    
            throw new Exception("No method $name and no behavior that implements it");
        }
    
        public function attach($behavior) {
            $this->behaviors[] = $behavior;
        }
    }
    
    class User extends Composable {}
    

    Test driver

    $user1 = new User;
    $user2 = new User;
    
    $user1->attach(new GrouppableBehavior);
    $user1->join('Test Group'); // works
    $user2->join('Test Group'); // throws
    

    See it in action.

    The main disadvantages of this approach are that it consumes more runtime resources and that behaviors can only access public members of the classes they are attaching to. In some cases you may find yourself forced to expose an implementation detail that should be private to enable a behavior to work.

    Dynamic approach #2: decorators

    A variation on behaviors is the decorator pattern:

    interface IUser {}
    
    interface IGrouppableUser extends IUser {
        public function join(...);
    }
    
    class User implements IUser {}
    
    class UserGroupingDecorator implements IGrouppableUser {
        private $realUser;
    
        public function __construct(IUser $realUser) {
            $this->realUser = $realUser;
        }
    
        public function join(...) { /* implementation */ }
    
        /* now you need to implement all IUser methods 
           and forward the calls to $this->realUser */
    
        /* if IUser exposes bare properties we have a problem! */
    }
    

    Using this pattern you can create a UserGroupingDecorator that wraps an IUser at will and pass the decorator to anything that accepts either an IUser or an IGrouppableUser.

    The main disadvantage of this approach is that it also does not provide access to the non-public members of User. In addition it rules out exposing bare properties from IUser as there is no way to “forward” bare property accesses from UserGroupingDecorator to $realUser if the properties are also defined on the former — and you cannot implement IGrouppableUser unless they are indeed defined. This state of affairs can be sidestepped by exposing properties as distinct getter/setter methods, but that means still more code to write.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have three tables which are defined as: class User(Base): __tablename__ = 'users' id
I have 2 web user controls, both inherit the same base class which extends
I have two models: User (email:string) Profile (name:string) class User < ActiveRecord::Base has_one :profile
I have this classes. user: class User < ActiveRecord::Base attr_accessible :email, :name has_many :berichten
I have a entity User(Base Class).Which have three child entity Admin ,Manager and Member
Say you have an abstract base class Task which is a task a user
Say I have the following class: class User(Base): __tablename__ = 'users' id = Column(Integer,
I have a user and nested profile class as follows: class User < ActiveRecord::Base
I have two models: User and Teacher : class User < ActiveRecord::Base attr_accessor :password
I have a simple model like this: class User < ActiveRecord::Base serialize :preferences end

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.