highperapp / uuid
High-performance UUID generator library implementing RFC 9562 with optional Rust FFI acceleration
Requires
- php: ^8.3
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- phpbench/phpbench: ^1.2
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
Suggests
- ext-bcmath: For arbitrary precision arithmetic fallback
- ext-ffi: For Rust FFI acceleration
- ext-gmp: For improved performance on 32-bit systems
- ext-openssl: For additional entropy sources
This package is auto-updated.
Last update: 2025-07-04 15:47:37 UTC
README
A high-performance UUID generator library implementing RFC 9562 with support for UUIDv1-v8, featuring optional Rust FFI acceleration, async/sync compatibility, and high-concurrency collision prevention.
Features
- ✅ Complete RFC 9562 Support: UUIDv1, v3, v4, v5, v6, v7, v8
- ⚡ High Performance: Optional Rust FFI acceleration
- 🔄 Async/Sync Compatible: Works with both paradigms seamlessly
- 🚀 Concurrency Support: RevoltPHP, AmphpV3, Parallel integration
- 🛡️ Collision Prevention: Advanced mechanisms for high-throughput scenarios
- 🔧 Configurable: Multiple RNG providers and performance options
- 📦 Zero Dependencies: Pure PHP fallback when FFI unavailable
- ✅ PHP 8.3+ Compatible: Supports PHP 8.3 and later versions
Installation
composer require highperapp/uuid
Optional: Rust FFI Acceleration
For maximum performance, you can enable Rust FFI acceleration which can improve UUID generation speed by up to 10x.
Prerequisites
-
Install PHP FFI Extension (required for Rust acceleration):
# Ubuntu/Debian sudo apt update sudo apt install php8.3-ffi php8.3-dev # CentOS/RHEL/Fedora sudo yum install php-ffi php-devel # or for newer versions: sudo dnf install php-ffi php-devel # macOS (with Homebrew) brew install php # FFI is usually included in modern PHP builds # Windows # Enable FFI in php.ini by uncommenting: # extension=ffi
-
Verify FFI Installation:
php -m | grep ffi # Should output: ffi # Test FFI functionality php -r "echo extension_loaded('ffi') ? 'FFI enabled' : 'FFI not available';"
-
Install Rust (if not already installed):
# Using rustup (recommended) curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source $HOME/.cargo/env # Or using your system package manager # Ubuntu/Debian: sudo apt install rustc cargo # macOS: brew install rust # Windows: Download from https://rustup.rs/
-
Verify Installation:
rustc --version cargo --version
Build the Rust Library
cd rust
cargo build --release
The compiled library will be available at rust/target/release/libuuid_ffi.so
(Linux/macOS) or rust/target/release/uuid_ffi.dll
(Windows).
Troubleshooting FFI Issues
If you encounter FFI-related errors:
-
FFI Not Available:
# Check if FFI is installed php -m | grep ffi # Check PHP configuration php --ini | grep "Configuration File" # Enable FFI in php.ini echo "extension=ffi" | sudo tee -a /etc/php/8.3/cli/php.ini
-
FFI Preloading Issues:
# Set FFI preload in php.ini (optional for better performance) echo "ffi.preload=" | sudo tee -a /etc/php/8.3/cli/php.ini
-
Permission Issues:
# Ensure the compiled library has proper permissions chmod +x rust/target/release/libuuid_ffi.so
-
Library Path Issues:
// Test FFI with absolute path $ffi = FFI::cdef("", __DIR__ . "/rust/target/release/libuuid_ffi.so");
Development vs Production
- Development: The library automatically falls back to pure PHP if Rust FFI is unavailable
- Production: For optimal performance, ensure both FFI extension and Rust library are available
- CI/CD: Add both FFI installation and Rust build steps to your deployment pipeline
- Docker: Include FFI in your PHP Docker image and build Rust during image creation
Quick Start
use HighPerApp\HighPer\Uuid\Core\UuidFactory; // Generate UUIDs $uuid4 = UuidFactory::v4(); // Random UUID $uuid7 = UuidFactory::v7(); // Timestamp-based UUID (recommended) $uuid1 = UuidFactory::v1(); // Legacy timestamp + MAC // Name-based UUIDs $uuid3 = UuidFactory::v3(UuidFactory::NAMESPACE_DNS, 'example.com'); $uuid5 = UuidFactory::v5(UuidFactory::NAMESPACE_DNS, 'example.com'); // Convert and validate $uuid = UuidFactory::fromString('550e8400-e29b-41d4-a716-446655440000'); $isValid = UuidFactory::isValid($uuid->toString()); echo $uuid->toString(); // 550e8400-e29b-41d4-a716-446655440000 echo $uuid->getVersion(); // 4
UUID Versions
UUIDv1 - Timestamp + MAC Address
$uuid = UuidFactory::v1(); echo $uuid->getTimestamp(); // Gregorian timestamp echo $uuid->getNode(); // MAC address (or random)
UUIDv3 - MD5 Name-based
$uuid = UuidFactory::v3Dns('example.com'); // Always generates the same UUID for the same input
UUIDv4 - Random
$uuid = UuidFactory::v4(); // Cryptographically random
UUIDv5 - SHA-1 Name-based
$uuid = UuidFactory::v5Url('https://example.com'); // Always generates the same UUID for the same input
UUIDv6 - Reordered Timestamp
$uuid = UuidFactory::v6(); // Like v1 but with better database locality
UUIDv7 - Unix Timestamp (Recommended)
$uuid = UuidFactory::v7(); // Best for new applications - sortable and efficient
UUIDv8 - Custom Format
$uuid = UuidFactory::v8([ 'custom_fields' => [ 'timestamp' => time(), 'counter' => 123 ] ]);
Performance Configuration
High Performance Setup
use HighPerApp\HighPer\Uuid\Core\Configuration; use HighPerApp\HighPer\Uuid\Core\UuidFactory; $config = Configuration::highPerformance(); UuidFactory::configure($config); // Now all UUID generation uses Rust FFI when available $uuid = UuidFactory::v4(); // Uses Rust acceleration
Custom Configuration
$config = Configuration::default() ->setDefaultVersion(7) ->setRandomProvider('rust') ->enableFFI(true) ->setMaxConcurrentWorkers(8); UuidFactory::configure($config);
Thread-Safe Operations
For concurrent environments (Swoole, ReactPHP, etc.), use the thread-safe factory:
use HighPerApp\HighPer\Uuid\Core\ThreadSafeUuidFactory; // Safe for concurrent environments $factory = ThreadSafeUuidFactory::getInstance(); $uuid = $factory->v4(); // Or use static convenience methods $uuid = ThreadSafeUuidFactory::createV4(); $uuid = ThreadSafeUuidFactory::createV7();
Async/Concurrent Generation
Prerequisites for Async Features
Install optional async dependencies for enhanced capabilities:
composer require revolt/event-loop amphp/amp amphp/parallel
Async Generation
use HighPerApp\HighPer\Uuid\Async\AsyncUuidFactory; // Check if async is available if (AsyncUuidFactory::isAsyncAvailable()) { // Single async UUID $uuid = AsyncUuidFactory::v4Async()->await(); $uuid = AsyncUuidFactory::v7Async()->await(); // Batch generation (non-blocking) $uuids = AsyncUuidFactory::generateBatch(1000, 4)->await(); // Concurrent batch with worker processes $uuids = AsyncUuidFactory::generateConcurrentBatch(10000, 4, 8)->await(); } else { // Fallback to synchronous $uuids = AsyncUuidFactory::generateBatchLegacy(1000, 4); }
High-Throughput Scenarios
use HighPerApp\HighPer\Uuid\Async\TrueConcurrentGenerator; // True parallel processing (requires amphp/parallel) $generator = new TrueConcurrentGenerator(8); // 8 worker processes $uuids = $generator->generateConcurrent(100000, 4); // Generates 100,000 UUIDs across 8 actual parallel processes
Pipeline Processing
use HighPerApp\HighPer\Uuid\Async\AsyncUuidFactory; // Stream-based generation with non-blocking yields foreach (AsyncUuidFactory::generatePipeline(10000, 7, 1000) as $uuid) { // Process each UUID as it's generated // Automatically yields control between batches echo $uuid->toString() . "\n"; }
Async Configuration
use HighPerApp\HighPer\Uuid\Configuration\AsyncConfiguration; // Configure for high-throughput $config = AsyncConfiguration::highThroughput(); AsyncUuidFactory::configure($config); // Or custom configuration $config = new AsyncConfiguration([ 'defaultWorkerCount' => 8, 'batchSize' => 5000, 'enableEntropyPool' => true, 'enableParallel' => true, ]); // Get optimal settings for your system $optimal = $config->getOptimalWorkerCount(); // Auto-detects CPU cores $batchSize = $config->getOptimalBatchSize(100000);
Random Number Providers
use HighPerApp\HighPer\Uuid\RandomProvider\RandomProviderFactory; // Available providers $providers = RandomProviderFactory::getAvailableProviders(); // ['secure', 'openssl', 'rust', 'pseudo'] // Create specific provider $provider = RandomProviderFactory::create('rust'); $uuid = UuidFactory::v4($provider); // Benchmark providers $results = RandomProviderFactory::benchmark('rust', 1000);
Collision Prevention
The library includes advanced collision prevention mechanisms:
use HighPerApp\HighPer\Uuid\Concurrency\CollisionPrevention; // Enable collision detection $config = Configuration::default() ->enableCollisionPrevention(true); UuidFactory::configure($config); // The library automatically handles: // - Timestamp collisions // - High-frequency generation // - Multi-process safety // - Sequence management
Benchmarking
Run performance tests to validate performance on your system:
# Run built-in benchmarks (requires PHPBench) vendor/bin/phpbench run benchmarks --report=default # Quick performance test php -r " require 'vendor/autoload.php'; use HighPerApp\HighPer\Uuid\Core\UuidFactory; \$start = microtime(true); for (\$i = 0; \$i < 10000; \$i++) { UuidFactory::v4(); } \$duration = microtime(true) - \$start; echo 'Generated ' . number_format(10000 / \$duration) . ' UUIDs/second\n'; "
Expected Performance Ranges
- Development environment: 300,000 - 600,000 UUIDs/second
- Production environment: 600,000 - 900,000 UUIDs/second
- With Rust FFI: 1,000,000+ UUIDs/second
- High-concurrency scenarios: 400,000 - 800,000 UUIDs/second
Performance depends on:
- CPU speed and architecture
- PHP version and configuration
- Available memory
- FFI extension availability
- Rust library compilation
Integration Examples
Laravel
// In a Laravel service provider use HighPerApp\HighPer\Uuid\Core\ThreadSafeUuidFactory; use HighPerApp\HighPer\Uuid\Async\AsyncUuidFactory; use HighPerApp\HighPer\Uuid\Configuration\AsyncConfiguration; public function register() { // Register thread-safe factory $this->app->singleton(ThreadSafeUuidFactory::class, function() { return ThreadSafeUuidFactory::getInstance(); }); } public function boot() { // Configure async capabilities if available if (AsyncUuidFactory::isAsyncAvailable()) { AsyncUuidFactory::configure(AsyncConfiguration::highThroughput()); } } // In your models protected $keyType = 'string'; public $incrementing = false; protected static function boot() { parent::boot(); static::creating(function ($model) { if (empty($model->id)) { $factory = app(ThreadSafeUuidFactory::class); $model->id = $factory->v7()->toString(); } }); } // In queue jobs for bulk operations class BulkUuidGenerationJob { public function handle() { if (AsyncUuidFactory::isAsyncAvailable()) { $uuids = AsyncUuidFactory::generateConcurrentBatch(50000, 7, 4)->await(); } else { $uuids = AsyncUuidFactory::generateBatchLegacy(50000, 7); } // Process the UUIDs } }
Symfony
# config/services.yaml services: HighPerApp\HighPer\Uuid\Core\ThreadSafeUuidFactory: factory: ['HighPerApp\HighPer\Uuid\Core\ThreadSafeUuidFactory', 'getInstance'] async_uuid_config: class: HighPerApp\HighPer\Uuid\Configuration\AsyncConfiguration factory: ['HighPerApp\HighPer\Uuid\Configuration\AsyncConfiguration', 'balanced']
// In a service or controller use HighPerApp\HighPer\Uuid\Core\ThreadSafeUuidFactory; use HighPerApp\HighPer\Uuid\Async\AsyncUuidFactory; class UuidService { public function __construct( private ThreadSafeUuidFactory $uuidFactory ) {} public function generateSingle(): string { return $this->uuidFactory->v7()->toString(); } public async function generateBatch(int $count): array { if (AsyncUuidFactory::isAsyncAvailable()) { return AsyncUuidFactory::generateBatch($count, 7)->await(); } return AsyncUuidFactory::generateBatchLegacy($count, 7); } }
Swoole/OpenSwoole Integration
use Swoole\Http\Server; use HighPerApp\HighPer\Uuid\Core\ThreadSafeUuidFactory; use HighPerApp\HighPer\Uuid\Async\AsyncUuidFactory; $server = new Server("127.0.0.1", 9501); $server->on('WorkerStart', function($server, $workerId) { // Reset static state for each worker ThreadSafeUuidFactory::resetInstance(); AsyncUuidFactory::reset(); }); $server->on('Request', function($request, $response) { // Thread-safe UUID generation $factory = ThreadSafeUuidFactory::getInstance(); $uuid = $factory->v7()->toString(); $response->end("Generated UUID: {$uuid}"); }); $server->start();
ReactPHP Integration
use React\EventLoop\Loop; use React\Http\HttpServer; use HighPerApp\HighPer\Uuid\Core\ThreadSafeUuidFactory; use HighPerApp\HighPer\Uuid\Async\AsyncUuidFactory; $loop = Loop::get(); $server = new HttpServer(function($request) { return new Promise(function($resolve) { if (AsyncUuidFactory::isAsyncAvailable()) { // Non-blocking UUID generation AsyncUuidFactory::generateBatch(1000, 7)->then(function($uuids) use ($resolve) { $resolve(new Response(200, [], json_encode($uuids))); }); } else { // Fallback to thread-safe synchronous $factory = ThreadSafeUuidFactory::getInstance(); $uuids = []; for ($i = 0; $i < 1000; $i++) { $uuids[] = $factory->v7()->toString(); } $resolve(new Response(200, [], json_encode($uuids))); } }); }); $socket = new SocketServer('127.0.0.1:8080', [], $loop); $server->listen($socket); $loop->run();
Database Storage
-- MySQL CREATE TABLE users ( id BINARY(16) PRIMARY KEY, uuid_string CHAR(36) GENERATED ALWAYS AS ( CONCAT( HEX(SUBSTR(id, 1, 4)), '-', HEX(SUBSTR(id, 5, 2)), '-', HEX(SUBSTR(id, 7, 2)), '-', HEX(SUBSTR(id, 9, 2)), '-', HEX(SUBSTR(id, 11, 6)) ) ) STORED, name VARCHAR(255) ); -- PostgreSQL CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE TABLE users ( id UUID PRIMARY KEY, name VARCHAR(255) );
Performance Characteristics
Version | Performance | Use Case | Sortable | Collision Risk |
---|---|---|---|---|
v1 | High | Legacy systems | No | Very Low |
v3 | Medium | Name-based, reproducible | No | None |
v4 | High | General purpose | No | Negligible |
v5 | Medium | Name-based, reproducible | No | None |
v6 | High | Sortable timestamp | Yes | Very Low |
v7 | Highest | Recommended for new apps | Yes | Very Low |
v8 | Variable | Custom implementations | Variable | Variable |
Throughput Benchmarks
Benchmarks measured on PHP 8.3.6, Linux x86_64. Performance may vary based on hardware and configuration.
Configuration | UUIDs/second | Memory/UUID | Notes |
---|---|---|---|
Pure PHP v4 | ~600,000-900,000 | <100 bytes | Actual performance exceeds estimates |
Pure PHP v7 | ~700,000-900,000 | <100 bytes | Recommended for new applications |
Pure PHP v1 | ~600,000 | <100 bytes | Legacy timestamp-based |
Pure PHP v3/v5 | ~850,000-900,000 | <100 bytes | Name-based UUIDs (cached) |
Rust FFI v4 | ~1,000,000+ | <50 bytes | Requires FFI extension + Rust build |
Rust FFI v7 | ~1,200,000+ | <50 bytes | Optimal for high-throughput scenarios |
Concurrent v4 | ~400,000-800,000 | Variable | Depends on worker count and overhead |
Memory Usage Notes:
- Memory per UUID is minimal in normal usage due to PHP's garbage collection
- Bulk operations (10,000+ UUIDs) may use ~100-200 bytes per UUID temporarily
- String representation adds ~36 bytes per UUID when stored
- Memory usage scales linearly with batch size
Configuration Options
$config = new Configuration(); // Version settings $config->setDefaultVersion(7); // Default: 7 // Performance settings $config->enableFFI(true); // Default: true $config->preferRustFFI(true); // Default: true $config->setMaxConcurrentWorkers(8); // Default: 4 // Security settings $config->setRandomProvider('secure'); // Default: 'secure' $config->enableCollisionPrevention(true); // Default: true // Timestamp settings $config->enableMonotonicTimestamp(true); // Default: true $config->setTimestampPrecision(1000); // microseconds // Namespaces $config->addNamespace('custom', 'your-namespace-uuid');
Error Handling
use HighPerApp\HighPer\Uuid\Exception\GenerationException; use HighPerApp\HighPer\Uuid\Exception\ValidationException; use HighPerApp\HighPer\Uuid\Exception\ConfigurationException; try { $uuid = UuidFactory::v3('invalid-namespace', 'name'); } catch (ValidationException $e) { // Handle validation errors } try { $uuid = UuidFactory::generate(99); // Invalid version } catch (GenerationException $e) { // Handle generation errors }
Development Setup
Prerequisites
-
PHP 8.3+ with extensions:
# Check required extensions php -m | grep -E "(ffi|openssl|json)" # Install missing extensions (Ubuntu/Debian) sudo apt install php8.3-ffi php8.3-openssl php8.3-json php8.3-dev # CentOS/RHEL/Fedora sudo yum install php-ffi php-openssl php-json php-devel # macOS (with Homebrew) brew install php # Verify FFI is working php -r "echo extension_loaded('ffi') ? 'FFI: ✓' : 'FFI: ✗';"
-
Composer (for PHP dependencies):
composer install
-
Rust (optional, for FFI acceleration):
# Install Rust if not already installed curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source $HOME/.cargo/env # Build the Rust library cd rust && cargo build --release # Verify Rust FFI library is built ls -la rust/target/release/libuuid_ffi.so
Development Workflow
# 1. Install dependencies composer install # 2. (Optional) Build Rust FFI for performance cd rust && cargo build --release && cd .. # 3. Run tests vendor/bin/phpunit # 4. Run static analysis vendor/bin/phpstan analyse
Testing
# Run tests vendor/bin/phpunit # Run with coverage vendor/bin/phpunit --coverage-html coverage # Run benchmarks vendor/bin/phpbench run benchmarks --report=default # Static analysis vendor/bin/phpstan analyse
Requirements
Core Requirements
- PHP 8.3 or higher
ext-openssl
(required for secure random generation)ext-json
(required for configuration)
Optional Dependencies
ext-ffi
(optional, for Rust FFI acceleration)revolt/event-loop
^1.0 (optional, for async operations)amphp/amp
^3.0 (optional, for async operations)amphp/parallel
^2.0 (optional, for concurrent processing)
Note: The library works perfectly without optional dependencies, providing graceful fallbacks.
FFI Configuration
For production environments, consider adding these settings to your php.ini
:
# Enable FFI extension extension=ffi # Optional: Preload FFI for better performance ; ffi.preload= # Optional: Set FFI scope (default is "preload") ; ffi.enable=preload
Contributing
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
MIT License. See LICENSE for details.