Model tournaments between teams In one of my projects I wrote a little tournament platform, but the way I handle participants is a bit messy and I want to clean this up.

So in my case a Tournament can have participants, but either a User or a Team can signup to become a participant. A participant now holds a user_id or a team_id in the database, and depending on which is filled I determine if a User is linked to the participant or if it's a team.

I rewrote the signup part of my Tournament model to accept both a User or a Team as parameter through am interface and was wondering if this is the correct way to go.

ICandidate.php

interface ICandidate
{
    public function getName();
    public function hasCorrectGamesSet($tournamentGame);
}


User.php

class User implements ICandidate
{
    private $game;

    public function __construct($game)
    {
        $this-&gt;game = $game;
    }

    public function getName()
    {
        return 'Username';
    }

    public function hasCorrectGamesSet($tournamentGame)
    {
        if($this-&gt;game != $tournamentGame){
            throw new Exception('Incorrect name');
        };

        return true;
    }
}


Team.php

class Team implements ICandidate
{
    private $users;

    public function __construct($users)
    {
        $this-&gt;users = $users;
    }

    public function getName()
    {
        return 'Teamname';
    }

    public function hasCorrectGamesSet($tournamentGame)
    {
        foreach($this-&gt;users as $user){
            $user-&gt;hasCorrectGamesSet($tournamentGame);
        }
    }
}


Participant.php

class Participant
{
    private $name;
    private $class;

    public function setName($name)
    {
        $this-&gt;name = $name;
    }

    public function setClass($class)
    {
        $this-&gt;class = $class;
    }
}


Tournament.php

class Tournament
{
    private $participants;
    private $game;

    public function __construct($game)
    {
        $this-&gt;game = $game;
    }

    public function signUp(ICandidate $candidate)
    {
        $candidate-&gt;hasCorrectGamesSet($this-&gt;game);

        $participant = new Participant();
        $participant-&gt;setName($candidate-&gt;getName());
        $participant-&gt;setClass(get_class($candidate));

        $this-&gt;participants[] = $participant;
    }

    public function getParticipants()
    {
        var_dump($this-&gt;participants);
    }
}


So with this set, I can signup a User or a Team, do a little check and if that passes, add them as a participant to the tournament.

Logic

$tournament = new Tournament('fifa');

$user1 = new User('fifa');
$user2 = new User('fifa');
$user3 = new User('fifa');
$user4 = new User('fifa');

$team = new Team([$user2, $user3, $user4]);

$tournament-&gt;signUp($user1);
$tournament-&gt;signUp($team);

$tournament-&gt;getParticipants();


Is this a correct way to implement this and make use of the interface?
Your code is actually much better than the average. Congrats.

I would change ICandidate to Candidate. No one needs to know if this is an interface, abstract class, concrete class, etc. Don't break encapsulation.

Also, using types makes your code more readable and less error prone.

I wouldn't also use getters and setters. For instance:

class Participant
{
    private string $name;
    private string $class;

    public function __construct(string $name, string $class)
    {
        $this-&gt;name = $name;
        $this-&gt;class = $class;
    }

    public function name(): string
    {
        return $this-&gt;name;
    }

    public function class(): string
    {
        return $this-&gt;class;
    }
}


But... do you really need the Participant class? From your example, it's not necessary.

In your Tournament class, $participants is an array of Candidates. 

Ah, I would also use namespaces so I would be able to implement autoloading (https://www.php-fig.org/psr/psr-4/)