What are the best practices for structuring a PHP class that interacts with a database for a ranking system?

When structuring a PHP class that interacts with a database for a ranking system, it is important to separate concerns by creating separate methods for retrieving, updating, and calculating rankings. Additionally, using prepared statements to prevent SQL injection attacks and error handling to manage database interactions are essential best practices.

class RankingSystem {
    private $db;

    public function __construct($db) {
        $this->db = $db;
    }

    public function getRankings() {
        $query = "SELECT * FROM rankings ORDER BY score DESC";
        $stmt = $this->db->prepare($query);
        $stmt->execute();
        return $stmt->fetchAll();
    }

    public function updateRanking($userId, $newScore) {
        $query = "UPDATE rankings SET score = :score WHERE user_id = :user_id";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':score', $newScore);
        $stmt->bindParam(':user_id', $userId);
        $stmt->execute();
    }

    public function calculateRank($userId) {
        $query = "SELECT COUNT(*) AS rank FROM rankings WHERE score > (SELECT score FROM rankings WHERE user_id = :user_id)";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':user_id', $userId);
        $stmt->execute();
        $result = $stmt->fetch();
        return $result['rank'] + 1;
    }
}