English | 简体中文
A lightweight PHP ID generator supporting Snowflake, UUID, timestamp, and readable ID strategies. Suitable for order numbers, database primary keys, log tracing, resource identifiers, and more.
🔗 Quickly understand this project's structure and code logic via Zread.
- Four built-in strategies: Snowflake, Timestamp, Readable, UUID — covering common ID generation needs
- Custom strategy support: Implement the
Generatorinterface and register your own strategy - Concurrency-safe: Built-in file lock and Redis lock, from single machine to distributed
- Parseable IDs: Extract timestamp, machine ID, sequence number, and more from generated IDs
- Lightweight with zero dependencies: Redis extension is optional; only PHP >= 8.1 required
- PHP >= 8.1
- ext-redis (optional, recommended for distributed scenarios)
composer require hejunjie/id-generatoruse Hejunjie\IdGenerator\IdGenerator;
// Create a Snowflake ID generator
$generator = IdGenerator::make('snowflake');
// Generate an ID
echo $generator->generate(); // 746532984356372480
// Parse an ID
print_r($generator->parse('746532984356372480'));
// [
// 'timestamp' => 1715779200000,
// 'datetime' => '2024-05-15 12:00:00',
// 'machine_id' => 256,
// 'sequence' => 0,
// ]64-bit Snowflake algorithm: 1-bit sign + 41-bit timestamp + 10-bit machine ID + 12-bit sequence number.
Configuration:
| Parameter | Type | Default | Description |
|---|---|---|---|
useFileLock |
bool |
false |
Enable file lock for concurrency safety |
redisConfig |
array |
[] |
Redis config; automatically uses Redis lock when provided |
Concurrency modes:
| Mode | Description | Use Case |
|---|---|---|
| Default (no lock) | Random sequence; duplicates possible at > 75 IDs/ms | Low-frequency calls |
| File lock | Safe on a single machine; slightly lower performance | Single server |
| Redis lock | Safe across distributed systems (recommended) | Distributed |
Note
The machine ID is automatically obtained via the MACHINE_ID environment variable, MAC address, or IP address. See Configuration for details.
use Hejunjie\IdGenerator\IdGenerator;
// Default (no lock)
$snowflake = IdGenerator::make('snowflake');
// Redis lock (recommended for distributed)
$snowflake = IdGenerator::make('snowflake', [
'redisConfig' => [
'host' => '127.0.0.1',
'port' => 6379,
'auth' => null, // omit if no password
],
]);
$id = $snowflake->generate();
print_r($snowflake->parse($id));Millisecond timestamp + sequence number, with optional custom prefix.
Configuration:
| Parameter | Type | Default | Description |
|---|---|---|---|
prefix |
string |
'' |
ID prefix; no prefix added if omitted |
useFileLock |
bool |
false |
Enable file lock for concurrency safety |
redisConfig |
array |
[] |
Redis config; automatically uses Redis lock when provided |
use Hejunjie\IdGenerator\IdGenerator;
// Timestamp ID with prefix
$timestamp = IdGenerator::make('timestamp', ['prefix' => 'ORD']);
$id = $timestamp->generate(); // ORD1715779200000123034
print_r($timestamp->parse($id));
// [
// 'prefix' => 'ORD',
// 'datetime' => '2024-05-15 12:00:00',
// 'timestamp' => 1715779200000,
// 'sequence' => '123034',
// ]Human-readable ID in the format PREFIX-YYYY-MM-DD-RANDOM. Ideal for user-facing scenarios.
Configuration:
| Parameter | Type | Default | Description |
|---|---|---|---|
prefix |
string |
'ID' |
ID prefix, automatically uppercased |
randomLength |
int |
8 |
Random string length (A-Z, 0-9) |
use Hejunjie\IdGenerator\IdGenerator;
$readable = IdGenerator::make('readable', ['prefix' => 'ORD', 'randomLength' => 6]);
$id = $readable->generate(); // ORD-2024-05-15-A3B9K2
print_r($readable->parse($id));
// [
// 'prefix' => 'ORD',
// 'date' => '2024-05-15',
// 'random' => 'A3B9K2',
// ]RFC 4122 compliant. Supports both v1 (time-based) and v4 (random).
Configuration:
| Parameter | Type | Default | Description |
|---|---|---|---|
version |
string |
'v4' |
UUID version: v1 or v4 |
use Hejunjie\IdGenerator\IdGenerator;
// UUID v4 (default)
$uuid = IdGenerator::make('uuid');
// UUID v1
$uuid = IdGenerator::make('uuid', ['version' => 'v1']);
$id = $uuid->generate(); // 550e8400-e29b-41d4-a716-446655440000
print_r($uuid->parse($id));
// [
// 'uuid' => '550e8400-e29b-41d4-a716-446655440000',
// 'version' => '4',
// ]Implement the Generator interface, then register with registerStrategy:
use Hejunjie\IdGenerator\Contracts\Generator;
use Hejunjie\IdGenerator\IdGenerator;
class MyCustomGenerator implements Generator
{
public function __construct(private string $prefix = 'MY') {}
public function generate(): string
{
return $this->prefix . '-' . random_int(1000, 9999);
}
public function parse(string $id): array
{
return ['id' => $id];
}
}
// Register
IdGenerator::registerStrategy('custom', function (array $config) {
return new MyCustomGenerator($config['prefix'] ?? 'MY');
});
// Use
$custom = IdGenerator::make('custom', ['prefix' => 'ORD']);
echo $custom->generate(); // ORD-4821The Snowflake strategy requires a 10-bit machine ID (0–1023). The resolution order is:
- Environment variable (recommended): set
MACHINE_IDto manually specify the machine ID - MAC address: automatically reads the network interface MAC address and hashes it
- IP address: falls back to IP address hashing when the above are unavailable
# Recommended: specify via environment variable at deploy time
export MACHINE_ID=1For distributed scenarios, configure Redis as follows:
[
'redisConfig' => [
'host' => '127.0.0.1',
'port' => 6379,
'auth' => null, // password; omit if none
],
]| Strategy | Use Case | Example ID |
|---|---|---|
| Snowflake | Distributed systems, DB primary keys, timestamp parsing | 746532984356372480 |
| Timestamp | Order numbers, transaction IDs, prefixed IDs | ORD1715779200000123034 |
| Readable | User-visible IDs, ticket numbers | ORD-2024-05-15-A3B9K2 |
| UUID | Standardized scenarios, third-party integrations | 550e8400-e29b-41d4-a716-446655440000 |
Snowflake's default mode uses a random sequence number, with collision risk when generating more than ~75 IDs per millisecond. This is typically safe for low-frequency use (e.g., a single ID per web request). For high-concurrency scenarios, use the Redis lock.
If redisConfig is provided but Redis is unavailable, generate() will throw an exception. Consider implementing error handling or a fallback strategy.
Issues and pull requests are welcome — whether it's new strategies, performance improvements, or documentation enhancements.
This project is licensed under the MIT License.