UUID Library v1.3.0

Binary UUID Functions

webpatser@dev: ~/uuid/1.3.0 $ cat binary-functions.md

Binary UUID Functions - UUID Library v1.3.0

Comprehensive guide to binary UUID operations for storage optimization, database performance, and memory efficiency. Learn how to work with UUIDs in their native 16-byte binary format.

Binary UUID Benefits
  • Storage Efficiency: 16 bytes vs 36 bytes (55% space savings)
  • Index Performance: Faster database operations with smaller indexes
  • Memory Usage: Reduced RAM consumption in large datasets
  • Network Transfer: Less bandwidth for UUID-heavy APIs

Basic Binary Operations

Converting to Binary Format

use Webpatser\Uuid\Uuid;
 
// Generate a UUID and get its binary representation
$uuid = Uuid::v4();
 
// Method 1: Using the bytes property
$binaryData = $uuid->bytes;
echo "Binary length: " . strlen($binaryData) . " bytes\n"; // 16 bytes
 
// Method 2: Converting from string
$uuidString = $uuid->string; // e.g., "550e8400-e29b-41d4-a716-446655440000"
$binaryFromString = pack('H*', str_replace('-', '', $uuidString));
 
// Verify they're identical
var_dump($binaryData === $binaryFromString); // true

Converting from Binary Format

// Convert binary data back to UUID string
function binaryToUuidString(string $binaryData): string
{
if (strlen($binaryData) !== 16) {
throw new InvalidArgumentException('Binary UUID must be exactly 16 bytes');
}
 
$hex = bin2hex($binaryData);
 
// Insert dashes at proper positions
return sprintf(
'%s-%s-%s-%s-%s',
substr($hex, 0, 8),
substr($hex, 8, 4),
substr($hex, 12, 4),
substr($hex, 16, 4),
substr($hex, 20, 12)
);
}
 
// Convert binary back to Uuid object
function binaryToUuid(string $binaryData): Uuid
{
$uuidString = binaryToUuidString($binaryData);
return Uuid::import($uuidString);
}
 
// Usage example
$originalUuid = Uuid::v4();
$binary = $originalUuid->bytes;
$restoredUuid = binaryToUuid($binary);
 
echo "Original: " . $originalUuid->string . "\n";
echo "Restored: " . $restoredUuid->string . "\n";
echo "Match: " . ($originalUuid->string === $restoredUuid->string ? "✓" : "✗") . "\n";

Database Storage Optimization

MySQL Binary Storage

-- Create table with binary UUID storage
CREATE TABLE users (
id BINARY(16) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 
-- Add index for performance
INDEX idx_users_id (id)
);
 
-- MySQL 8.0+ has built-in UUID functions
-- But we'll show manual approach for compatibility
// PHP class for MySQL binary UUID operations
class MySQLBinaryUuid
{
private PDO $pdo;
 
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
 
// Insert user with binary UUID
public function createUser(string $name, string $email): string
{
$uuid = Uuid::v4();
$binaryId = $uuid->bytes;
 
$stmt = $this->pdo->prepare("
INSERT INTO users (id, name, email)
VALUES (?, ?, ?)
");
 
$stmt->execute([$binaryId, $name, $email]);
 
return $uuid->string; // Return string format for API
}
 
// Retrieve user by UUID string
public function getUser(string $uuidString): ?array
{
$uuid = Uuid::import($uuidString);
$binaryId = $uuid->bytes;
 
$stmt = $this->pdo->prepare("
SELECT BIN_TO_UUID(id) as id, name, email, created_at
FROM users
WHERE id = ?
");
 
$stmt->execute([$binaryId]);
return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}
 
// Get all users with proper UUID formatting
public function getAllUsers(): array
{
$stmt = $this->pdo->query("
SELECT id, name, email, created_at
FROM users
ORDER BY created_at DESC
");
 
$users = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// Convert binary ID back to string
$row['id'] = $this->binaryToUuidString($row['id']);
$users[] = $row;
}
 
return $users;
}
 
private function binaryToUuidString(string $binary): string
{
$hex = bin2hex($binary);
return sprintf(
'%s-%s-%s-%s-%s',
substr($hex, 0, 8),
substr($hex, 8, 4),
substr($hex, 12, 4),
substr($hex, 16, 4),
substr($hex, 20, 12)
);
}
}
 
// Usage
$pdo = new PDO('mysql:host=localhost;dbname=test', $username, $password);
$userRepo = new MySQLBinaryUuid($pdo);
 
$userId = $userRepo->createUser('John Doe', '[email protected]');
$user = $userRepo->getUser($userId);
 
echo "Created user: " . $user['name'] . " (ID: " . $user['id'] . ")\n";

PostgreSQL Binary Storage

-- PostgreSQL has native UUID type, but we can still use binary for optimization
CREATE TABLE users (
id BYTEA PRIMARY KEY, -- 16-byte binary storage
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
 
-- Create index on binary UUID
CREATE INDEX idx_users_binary_id ON users(id);
// PostgreSQL binary UUID operations
class PostgreSQLBinaryUuid
{
private PDO $pdo;
 
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
 
public function createUser(string $name, string $email): string
{
$uuid = Uuid::v7(); // Use v7 for better performance
$binaryId = $uuid->bytes;
 
$stmt = $this->pdo->prepare("
INSERT INTO users (id, name, email)
VALUES (?, ?, ?)
");
 
$stmt->bindParam(1, $binaryId, PDO::PARAM_LOB);
$stmt->bindParam(2, $name);
$stmt->bindParam(3, $email);
$stmt->execute();
 
return $uuid->string;
}
 
public function getUser(string $uuidString): ?array
{
$uuid = Uuid::import($uuidString);
$binaryId = $uuid->bytes;
 
$stmt = $this->pdo->prepare("
SELECT id, name, email, created_at
FROM users
WHERE id = ?
");
 
$stmt->bindParam(1, $binaryId, PDO::PARAM_LOB);
$stmt->execute();
 
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result) {
// Convert binary back to string
$result['id'] = $this->binaryToUuidString(stream_get_contents($result['id']));
}
 
return $result ?: null;
}
 
private function binaryToUuidString(string $binary): string
{
$hex = bin2hex($binary);
return sprintf(
'%s-%s-%s-%s-%s',
substr($hex, 0, 8),
substr($hex, 8, 4),
substr($hex, 12, 4),
substr($hex, 16, 4),
substr($hex, 20, 12)
);
}
}

Performance Comparison

Storage Size Comparison
Format Size Example Space Savings
String (with dashes) 36 bytes 550e8400-e29b-41d4-a716-446655440000 Baseline
String (no dashes) 32 bytes 550e8400e29b41d4a716446655440000 11% smaller
Binary 16 bytes [16 bytes of binary data] 55% smaller

Benchmark Results

// Benchmark binary vs string UUID performance
function benchmarkUuidFormats(int $iterations = 100000): void
{
echo "Benchmarking UUID formats with {$iterations} iterations...\n\n";
 
// Generate test UUIDs
$uuids = [];
for ($i = 0; $i < $iterations; $i++) {
$uuids[] = Uuid::v4();
}
 
// String format benchmark
$start = microtime(true);
$stringSize = 0;
foreach ($uuids as $uuid) {
$stringData = $uuid->string;
$stringSize += strlen($stringData);
}
$stringTime = microtime(true) - $start;
 
// Binary format benchmark
$start = microtime(true);
$binarySize = 0;
foreach ($uuids as $uuid) {
$binaryData = $uuid->bytes;
$binarySize += strlen($binaryData);
}
$binaryTime = microtime(true) - $start;
 
// Results
echo "String Format:\n";
echo " Time: " . number_format($stringTime * 1000, 2) . "ms\n";
echo " Size: " . number_format($stringSize / 1024, 2) . " KB\n";
echo " Avg per UUID: " . ($stringSize / $iterations) . " bytes\n\n";
 
echo "Binary Format:\n";
echo " Time: " . number_format($binaryTime * 1000, 2) . "ms\n";
echo " Size: " . number_format($binarySize / 1024, 2) . " KB\n";
echo " Avg per UUID: " . ($binarySize / $iterations) . " bytes\n\n";
 
$spaceSavings = (($stringSize - $binarySize) / $stringSize) * 100;
$speedDiff = ($stringTime - $binaryTime) / $stringTime * 100;
 
echo "Savings:\n";
echo " Space: " . number_format($spaceSavings, 1) . "%\n";
echo " Speed: " . number_format($speedDiff, 1) . "% faster\n";
}
 
// Run benchmark
benchmarkUuidFormats(50000);

Live Performance Test

0.05ms
String Format (1000 UUIDs)
35.16 KB total
0.04ms
Binary Format (1000 UUIDs)
15.63 KB total
55.6%
Space Savings
20000 bytes saved

Live benchmark results generated on page load

Advanced Binary Operations

Bulk Binary Processing

class BinaryUuidProcessor
{
// Convert array of UUID strings to binary format
public static function stringArrayToBinary(array $uuidStrings): array
{
return array_map(function (string $uuidString): string {
$uuid = Uuid::import($uuidString);
return $uuid->bytes;
}, $uuidStrings);
}
 
// Convert array of binary UUIDs to strings
public static function binaryArrayToString(array $binaryUuids): array
{
return array_map(function (string $binary): string {
return self::binaryToUuidString($binary);
}, $binaryUuids);
}
 
// Efficient batch UUID generation in binary format
public static function generateBinaryBatch(int $count, int $version = 4): array
{
$binaries = [];
for ($i = 0; $i < $count; $i++) {
$uuid = match($version) {
1 => Uuid::generate(1),
4 => Uuid::v4(),
7 => Uuid::v7(),
default => Uuid::v4()
};
$binaries[] = $uuid->bytes;
}
return $binaries;
}
 
// Pack multiple binary UUIDs into a single string
public static function packBinaryUuids(array $binaryUuids): string
{
return implode('', $binaryUuids);
}
 
// Unpack multiple binary UUIDs from a single string
public static function unpackBinaryUuids(string $packedData): array
{
if (strlen($packedData) % 16 !== 0) {
throw new InvalidArgumentException('Packed data length must be multiple of 16');
}
 
$uuids = [];
$count = strlen($packedData) / 16;
 
for ($i = 0; $i < $count; $i++) {
$uuids[] = substr($packedData, $i * 16, 16);
}
 
return $uuids;
}
 
private static function binaryToUuidString(string $binary): string
{
$hex = bin2hex($binary);
return sprintf(
'%s-%s-%s-%s-%s',
substr($hex, 0, 8),
substr($hex, 8, 4),
substr($hex, 12, 4),
substr($hex, 16, 4),
substr($hex, 20, 12)
);
}
}
 
// Usage examples
$uuidStrings = [
'550e8400-e29b-41d4-a716-446655440000',
'6ba7b810-9dad-11d1-80b4-00c04fd430c8',
'6ba7b811-9dad-11d1-80b4-00c04fd430c8'
];
 
// Convert to binary
$binaryUuids = BinaryUuidProcessor::stringArrayToBinary($uuidStrings);
echo "Converted " . count($binaryUuids) . " UUIDs to binary\n";
 
// Pack for storage/transmission
$packed = BinaryUuidProcessor::packBinaryUuids($binaryUuids);
echo "Packed size: " . strlen($packed) . " bytes\n";
 
// Unpack and convert back
$unpacked = BinaryUuidProcessor::unpackBinaryUuids($packed);
$restored = BinaryUuidProcessor::binaryArrayToString($unpacked);
 
echo "Original: " . json_encode($uuidStrings) . "\n";
echo "Restored: " . json_encode($restored) . "\n";

Binary UUID Validation

class BinaryUuidValidator
{
// Validate binary UUID format
public static function isValidBinary(string $binary): bool
{
// Must be exactly 16 bytes
if (strlen($binary) !== 16) {
return false;
}
 
// Convert to hex and check UUID structure
$hex = bin2hex($binary);
 
// Check version and variant bits
$version = hexdec(substr($hex, 12, 1));
$variant = hexdec(substr($hex, 16, 1));
 
// Version should be 1, 3, 4, 5, 6, 7, or 8
if (!in_array($version, [1, 3, 4, 5, 6, 7, 8])) {
return false;
}
 
// Variant should be 8, 9, A, or B (10xx in binary)
if (($variant & 0xC) !== 0x8) {
return false;
}
 
return true;
}
 
// Extract UUID version from binary
public static function getVersion(string $binary): int
{
if (!self::isValidBinary($binary)) {
throw new InvalidArgumentException('Invalid binary UUID');
}
 
$hex = bin2hex($binary);
return hexdec(substr($hex, 12, 1));
}
 
// Check if binary UUID is nil (all zeros)
public static function isNil(string $binary): bool
{
return $binary === str_repeat("\x00", 16);
}
 
// Generate nil UUID in binary format
public static function nil(): string
{
return str_repeat("\x00", 16);
}
}
 
// Usage examples
$uuid = Uuid::v4();
$binary = $uuid->bytes;
 
echo "Valid binary UUID: " . (BinaryUuidValidator::isValidBinary($binary) ? "✓" : "✗") . "\n";
echo "Version: " . BinaryUuidValidator::getVersion($binary) . "\n";
echo "Is nil: " . (BinaryUuidValidator::isNil($binary) ? "✓" : "✗") . "\n";
 
// Test with nil UUID
$nilBinary = BinaryUuidValidator::nil();
echo "Nil UUID valid: " . (BinaryUuidValidator::isValidBinary($nilBinary) ? "✓" : "✗") . "\n";
echo "Nil UUID is nil: " . (BinaryUuidValidator::isNil($nilBinary) ? "✓" : "✗") . "\n";

Laravel Integration

// Laravel model with binary UUID support
use Illuminate\Database\Eloquent\Model;
use Webpatser\Uuid\Uuid;
 
class BinaryUuidModel extends Model
{
protected $keyType = 'string';
public $incrementing = false;
 
// Automatically handle binary UUID conversion
protected $casts = [
'id' => 'string',
];
 
protected static function boot()
{
parent::boot();
 
static::creating(function ($model) {
if (!$model->id) {
$uuid = Uuid::v7(); // Time-ordered for better performance
// Store as binary in database, but keep string in model
$model->id = $uuid->string;
}
});
}
 
// Custom accessor to handle binary storage
public function getIdAttribute($value)
{
if (is_string($value) && strlen($value) === 16) {
// Convert binary to string
return $this->binaryToUuidString($value);
}
return $value;
}
 
// Custom mutator to store as binary
public function setIdAttribute($value)
{
if (is_string($value) && strlen($value) === 36) {
// Convert string to binary for storage
$uuid = Uuid::import($value);
$this->attributes['id'] = $uuid->bytes;
} else {
$this->attributes['id'] = $value;
}
}
 
private function binaryToUuidString(string $binary): string
{
$hex = bin2hex($binary);
return sprintf(
'%s-%s-%s-%s-%s',
substr($hex, 0, 8),
substr($hex, 8, 4),
substr($hex, 12, 4),
substr($hex, 16, 4),
substr($hex, 20, 12)
);
}
}
 
// Migration for binary UUID column
// In your migration file:
Schema::create('binary_uuid_models', function (Blueprint $table) {
$table->binary('id', 16)->primary(); // 16-byte binary column
$table->string('name');
$table->timestamps();
});

Best Practices

Binary UUID Best Practices
  • Always validate: Check binary data is exactly 16 bytes before processing
  • Use UUID v7: Time-ordered UUIDs perform better in binary indexes
  • Index binary columns: Create proper database indexes on binary UUID columns
  • Handle endianness: Be aware of byte order when working across systems
  • Document format: Clearly specify when APIs expect binary vs string UUIDs
  • Batch operations: Process multiple UUIDs together for better performance
  • Error handling: Gracefully handle invalid binary data
  • Testing: Test binary/string conversions thoroughly

Troubleshooting

Common Binary UUID Issues
Issue: "Invalid binary length" errors
Fix: Ensure binary data is exactly 16 bytes, check for truncation
Issue: Database constraint violations
Fix: Verify binary UUID format before insertion, check unique constraints
Issue: Performance degradation
Fix: Add proper indexes on binary UUID columns, consider UUID v7
Issue: Cross-platform compatibility
Fix: Test binary UUID handling across different systems and databases

Conclusion

Binary UUID operations provide significant storage and performance benefits, especially for large-scale applications. The 55% space savings and improved index performance make binary UUIDs ideal for high-volume database operations.

Key takeaways:

  • Binary UUIDs use 16 bytes vs 36 bytes for string format
  • Database indexes are more efficient with binary data
  • Proper conversion functions are essential for data integrity
  • UUID v7 provides optimal performance for time-ordered data
  • Always validate binary UUID format and length