php 58 lines · 8 steps

A fixed-window rate limiter on APCu

A small PHP class counts requests per key in shared memory and resets the count after a fixed time window.

Explained by highlit
1<?php
2 
3namespace App\Security;
4 
5use RuntimeException;
6 
7final class ApcuRateLimiter
8{
9 public function __construct(
10 private readonly int $limit = 60,
11 private readonly int $window = 60,
12 private readonly string $prefix = 'ratelimit:'
13 ) {
14 if (!\function_exists('apcu_inc')) {
15 throw new RuntimeException('APCu extension is not available.');
16 }
17 }
18 
19 public function attempt(string $key): bool
20 {
21 return $this->hits($key) <= $this->limit;
22 }
23 
24 public function hits(string $key): int
25 {
26 $bucket = $this->prefix . $key;
27 $success = false;
28 $count = apcu_inc($bucket, 1, $success);
29 
30 if (!$success || $count === 1) {
31 apcu_store($bucket, 1, $this->window);
32 return 1;
33 }
34 
35 return $count;
36 }
37 
38 public function remaining(string $key): int
39 {
40 $current = (int) apcu_fetch($this->prefix . $key);
41 return max(0, $this->limit - $current);
42 }
43 
44 public function retryAfter(string $key): int
45 {
46 $info = apcu_key_info($this->prefix . $key);
47 if ($info === null) {
48 return 0;
49 }
50 $expiresAt = $info['creation_time'] + $info['ttl'];
51 return max(0, $expiresAt - time());
52 }
53 
54 public function clear(string $key): void
55 {
56 apcu_delete($this->prefix . $key);
57 }
58}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1An atomic increment is the heart of a rate limiter — it lets concurrent requests share one counter without races.
  2. 2The fixed-window scheme is implemented by attaching a TTL only when the counter first appears, so it expires and resets automatically.
  3. 3Separating attempt, remaining, and retryAfter gives callers everything they need to enforce limits and build informative responses.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A fixed-window rate limiter on APCu — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code