PHPackages                             chasecrawford/ratings - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. chasecrawford/ratings

AbandonedLibrary[Utility &amp; Helpers](/categories/utility)

chasecrawford/ratings
=====================

A PHP class which implements the Elo rating system &amp; Rating Percentage index

1.0.0(3y ago)1131PHPPHP &gt;=8.0CI passing

Since Jan 11Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/chasecrawford/ratings)[ Packagist](https://packagist.org/packages/chasecrawford/ratings)[ Docs](https://github.com/chasecrawford/ratings)[ RSS](/packages/chasecrawford-ratings/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (1)DependenciesVersions (3)Used By (0)

Ratings
=======

[](#ratings)

[![CI](https://github.com/chasecrawford/ratings/actions/workflows/ci.yml/badge.svg)](https://github.com/chasecrawford/ratings/actions/workflows/ci.yml)[![codecov](https://camo.githubusercontent.com/97368910a559bd38fc10d97df4037b1a26d9f33ef7bb5e23a57a67f2bc76049c/68747470733a2f2f636f6465636f762e696f2f67682f636861736563726177666f72642f726174696e67732f6272616e63682f6d61696e2f67726170682f62616467652e737667)](https://codecov.io/gh/chasecrawford/ratings)[![Latest Version](https://camo.githubusercontent.com/421a8a8e11a6257654b6728030103012705cfcc1b23a98ad23a677d187ec7d08/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f636861736563726177666f72642f726174696e67732e737667)](https://packagist.org/packages/chasecrawford/ratings)[![PHP Version](https://camo.githubusercontent.com/4805af76668ce3114ba2903e001ce9272a31b44fc616271e6ed071f91bd35a23/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f636861736563726177666f72642f726174696e67732e737667)](https://packagist.org/packages/chasecrawford/ratings)[![License](https://camo.githubusercontent.com/d5ab17ee968f77ab2c3dfc0bac1cc291d8c8af64053680a3bf1b44747d5eb394/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f636861736563726177666f72642f726174696e67732e737667)](LICENSE)

A typed, dependency-free PHP library implementing the **Elo**, **Glicko-2**, and **RPI** rating systems. Pure-calculator design: feed in match data, get rating updates back. No accumulators, no global state, no I/O — drop into any consumer project (Laravel, Symfony, raw scripts, queue workers).

Install
-------

[](#install)

```
composer require chasecrawford/ratings
```

Requires PHP 8.2+.

Quick start (Elo)
-----------------

[](#quick-start-elo)

```
use ChaseCrawford\Ratings\Common\Outcome;
use ChaseCrawford\Ratings\Elo\{EloCalculator, EloRating, ConstantK};

$elo = new EloCalculator(new ConstantK(k: 20));
$update = $elo->rate(
    a: new EloRating(1500),
    b: new EloRating(1400),
    outcomeForA: Outcome::WIN,
);

echo $update->newA->value;  // ~1507.20
echo $update->expectedA;    // ~0.640 (pre-match win probability)
```

Elo
---

[](#elo)

```
use ChaseCrawford\Ratings\Elo\{EloCalculator, EloRating, ConstantK, UscfK, CallableK};
use ChaseCrawford\Ratings\Common\Outcome;

// K-factor strategies:
$elo = new EloCalculator(new ConstantK(15));   // simple constant
$elo = new EloCalculator(new UscfK());         // USCF tiered (40 provisional, then 32/24/16 by rating)
$elo = new EloCalculator(new CallableK(        // your own logic
    fn(EloRating $r, int $matches) => $r->value > 2400 ? 10 : 24
));

$update = $elo->rate(
    a: new EloRating(1500),
    b: new EloRating(1400),
    outcomeForA: Outcome::WIN,
    matchesPlayedA: 42,   // optional, used by UscfK and CallableK
    matchesPlayedB: 12,
);
```

Glicko-2
--------

[](#glicko-2)

Glicko-2 carries three numbers per player — rating, deviation (uncertainty), and volatility — and is updated in *rating periods* (e.g., weekly). You give the calculator one player's pre-period state and the list of opponents they faced; you get their new state back.

```
use ChaseCrawford\Ratings\Glicko\{Glicko2Calculator, GlickoRating, PeriodMatch};
use ChaseCrawford\Ratings\Common\Outcome;

$glicko = new Glicko2Calculator(tau: 0.5);   // system constant; 0.3–1.2 reasonable

$alice = new GlickoRating(rating: 1500, deviation: 200, volatility: 0.06);

$newAlice = $glicko->updatePlayer($alice, [
    new PeriodMatch(new GlickoRating(1400, 30), Outcome::WIN),
    new PeriodMatch(new GlickoRating(1550, 100), Outcome::LOSS),
    new PeriodMatch(new GlickoRating(1700, 300), Outcome::LOSS),
]);

// Empty period = deviation grows (decay):
$idle = $glicko->updatePlayer($alice, []);
```

RPI
---

[](#rpi)

RPI (Rating Percentage Index) is a *seasonal aggregate* — compute from a body of game results all at once.

```
use ChaseCrawford\Ratings\Rpi\{RpiCalculator, GameResult, Weights};
use ChaseCrawford\Ratings\Common\Outcome;

$rpi = new RpiCalculator();   // defaults to classic 25/50/25 weights
// or: new RpiCalculator(new Weights(own: 0.30, opponents: 0.50, opponentsOpponents: 0.20))

$result = $rpi->rate([
    new GameResult('Duke',     'UNC',      Outcome::WIN),
    new GameResult('Duke',     'NC State', Outcome::LOSS),
    new GameResult('UNC',      'NC State', Outcome::WIN),
    // ... a season's worth
]);

$result->ratings['Duke'];   // computed RPI
$result->ranked();          // ['Duke' => 0.62, 'UNC' => 0.51, …] sorted descending
```

Common patterns
---------------

[](#common-patterns)

```
use ChaseCrawford\Ratings\Common\Outcome;

// Convert from raw scores:
Outcome::fromScores(myScore: 5, theirScore: 3);   // Outcome::WIN

// Numeric value for Elo/Glicko math:
Outcome::WIN->score();   // 1.0
Outcome::DRAW->score();  // 0.5
Outcome::LOSS->score();  // 0.0

// "From the other side's view":
Outcome::WIN->inverse();   // Outcome::LOSS
```

All exceptions extend `ChaseCrawford\Ratings\Common\Exception\RatingException`, with two subclasses: `InvalidRatingException` (NaN, negative deviation, etc.) and `InvalidConfigurationException` (weights don't sum to 1.0, self-play, etc.).

Choosing an algorithm
---------------------

[](#choosing-an-algorithm)

AlgorithmBest forPer-player stateUpdate model**Elo**Pairwise head-to-head, simple to explain, needs few games to start working1 number (rating)One match at a time**Glicko-2**When you care about *uncertainty* — players who haven't played recently or have few games should be rated less confidently3 numbers (rating, deviation, volatility)Batch by rating period (e.g., weekly)**RPI**Season-end rankings where strength of schedule matters; college sports traditionNone — recomputed each timeAggregate over a body of gamesVersioning
----------

[](#versioning)

Strict semver from v2.0.0. Major bumps for any breaking API change. The v1 line (`^1.0`) is unmaintained and incompatible with v2.

Contributing
------------

[](#contributing)

See [CONTRIBUTING.md](CONTRIBUTING.md).

License
-------

[](#license)

[MIT](LICENSE) © Chase Crawford

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance61

Regular maintenance activity

Popularity8

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 53.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

1269d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/8802851b949049e63a4a5f4791f58fe6bf20d9d39480d99c01faea9b06077162?d=identicon)[chasecrawford](/maintainers/chasecrawford)

---

Top Contributors

[![chasecrawford](https://avatars.githubusercontent.com/u/1011988?v=4)](https://github.com/chasecrawford "chasecrawford (14 commits)")[![ccrawfordhatfield](https://avatars.githubusercontent.com/u/52418819?v=4)](https://github.com/ccrawfordhatfield "ccrawfordhatfield (12 commits)")

---

Tags

indexsystempercentageRatingrankingelorpi

### Embed Badge

![Health badge](/badges/chasecrawford-ratings/health.svg)

```
[![Health](https://phpackages.com/badges/chasecrawford-ratings/health.svg)](https://phpackages.com/packages/chasecrawford-ratings)
```

###  Alternatives

[symfony/property-access

Provides functions to read and write from/to an object or array using a simple string notation

2.8k317.3M3.2k](/packages/symfony-property-access)[rubix/ml

A high-level machine learning and deep learning library for the PHP language.

2.2k1.5M28](/packages/rubix-ml)[kartik-v/bootstrap-star-rating

A simple yet powerful JQuery star rating plugin for Bootstrap.

1.1k4.7M5](/packages/kartik-v-bootstrap-star-rating)[spatie/laravel-robots-middleware

Add an `all` or `none` robots header to your requests via a middleware in Laravel

3372.2M5](/packages/spatie-laravel-robots-middleware)[willvincent/laravel-rateable

Allows multiple models to be rated with a fivestar like system.

415468.6k3](/packages/willvincent-laravel-rateable)[kartik-v/yii2-widget-rating

A Yii2 widget for the simple yet powerful bootstrap-star-rating plugin with fractional rating support (sub repo split from yii2-widgets)

474.3M8](/packages/kartik-v-yii2-widget-rating)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
