ez-php / support
General-purpose utility classes for the ez-php ecosystem — Range, WeightedRandom, TimeProbability, DailyQuota
Requires
- php: ^8.5
Requires (Dev)
- ez-php/docker: ^2.0
- friendsofphp/php-cs-fixer: ^3.94
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- 2.5.6
- 2.5.5
- 2.5.4
- 2.5.3
- 2.5.2
- 2.5.1
- 2.5.0
- 2.4.11
- 2.4.10
- 2.4.9
- 2.4.8
- 2.4.7
- 2.4.6
- 2.4.5
- 2.4.4
- 2.4.3
- 2.4.2
- 2.4.1
- 2.4.0
- 2.3.9
- 2.3.8
- 2.3.7
- 2.3.6
- 2.3.5
- 2.3.4
- 2.3.3
- 2.3.2
- 2.3.1
- 2.3.0
- 2.2.1
- 2.2.0
- 2.1.1
- 2.1.0
- 2.0.1
- 2.0.0
- 1.14.0
- 1.13.1
- 1.13.0
- 1.12.2
- 1.12.1
- 1.12.0
- 1.11.2
- 1.11.1
- 1.11.0
- 1.10.0
- 1.9.2
- 1.9.1
- 1.9.0
- 1.8.0
This package is auto-updated.
Last update: 2026-09-30 19:50:26 UTC
README
General-purpose utility classes for the ez-php ecosystem. Zero external dependencies — pure PHP.
Classes
Range
Immutable value object for a bounded integer range.
$r = Range::of(0, 100); $r->contains(50); // true $r->clamp(150); // 100 $r->random(); // uniform draw in [0, 100] $r->weightedLow(); // min-of-two-draws, skewed towards 0
WeightedRandom
Stateless weighted random selection from a list of associative arrays.
$items = [ ['name' => 'common', 'weight' => 9], ['name' => 'rare', 'weight' => 1], ]; WeightedRandom::pick($items); // picks one, respecting weights WeightedRandom::pickN($items, 2); // picks 2 without replacement WeightedRandom::weightedLow(0, 100); // min-of-two-draws
Custom weight key:
WeightedRandom::pick($items, 'probability');
TimeProbability
Exponential time-based probability curve: P(t) = 1 − exp(−t / λ).
// Deterministic: just the probability value TimeProbability::probability(minutesSince: 5.0, lambda: 4.0); // ~0.713 // Stochastic: roll the curve TimeProbability::exponential(minutesSince: 5.0); // true/false
Always returns true once minutesSince >= hardCapMinutes (default 15).
DailyQuota
Immutable value object for "daily allowance + per-action growing cooldown + UTC midnight reset".
$quota = new DailyQuota(dailyLimit: 5, cooldownBaseSeconds: 300, cooldownStepSeconds: 300); $now = new DateTimeImmutable(); if ($quota->canPerform($now)) { $quota = $quota->perform($now); // persist $quota state } $quota->remaining(); // actions left today $quota->cooldownUntil(); // next available time $quota->usedToday(); // actions performed today
UTC midnight resets happen automatically inside canPerform() and perform(). Call
resetIfNeeded($now) explicitly to get a fresh instance without performing an action.
XpProgression / LevelUpResult
Configurable exponential XP curve — the threshold for level N is floor(base × N^exponent).
XP accumulates and is never reset, so one call can cross several levels.
$curve = new XpProgression(base: 100, exponent: 1.5); $curve->xpForLevel(4); // 800 $result = $curve->applyXp(currentXp: 250, currentLevel: 1, gained: 600); $result->newXp(); // 850 $result->newLevel(); // 4 $result->levelUps(); // 3 $result->didLevelUp(); // true
DimensionSet
Immutable set of named dimensions, each clamped to [0, 100] — personality, mood,
reputation, skill stats.
$mood = new DimensionSet(['joy' => 40, 'anger' => 10]); $mood = $mood->apply(['joy' => 30, 'fear' => 5]); // joy 70, anger 10, fear 5 $mood->get('joy'); // 70 $mood->dominant(50); // 'joy' (highest value strictly above 50), or null $mood->all(); // ['joy' => 70, 'anger' => 10, 'fear' => 5]
Coordinate / InfiniteGrid
Coordinate is a readonly (x, y) pair; InfiniteGrid does stateless tile math for
8-directional grids using the Chebyshev metric (diagonals cost the same as cardinals).
InfiniteGrid::adjacentCoordinates(0, 0); // 8 Coordinate neighbours InfiniteGrid::isAdjacent(0, 0, 1, 1); // true InfiniteGrid::chebyshevDistance(0, 0, 3, -2); // 3 InfiniteGrid::tilesInRadius(0, 0, 1); // 9 tiles, centre included
CronExpression
Minimal five-field cron matcher (minute hour day-of-month month day-of-week), used by
ez-php/scheduler and ez-php/queue.
CronExpression::isDue('*/15 * * * *', new DateTimeImmutable()); // every 15 minutes CronExpression::isDue('0 6 * * 1', $now); // Mondays at 06:00
Supports *, N and */N per field; day-of-week is 0–6 with Sunday = 0. Ranges, lists
and names are not supported. A malformed expression (not exactly five fields) is never due.
Installation
composer require ez-php/support
Testing
composer full