glhd/bits
Generate unique 64-bit IDs in PHP for distributed systems. Create Twitter Snowflake, Sonyflake, or custom bit-sequence identifiers. Configure worker/datacenter IDs and a custom epoch to avoid collisions across servers.
Install the package:
composer require glhd/bits
Configure environment variables (critical for distributed systems):
BITS_WORKER_ID=1 # Unique per worker (0-31)
BITS_DATACENTER_ID=1 # Unique per datacenter (0-31)
BITS_EPOCH=2023-01-01 # Default; adjust if testing with past dates
First use case: Generate a Snowflake ID in a controller or service:
use Glhd\Bits\Snowflake;
$id = Snowflake::make(); // Returns Snowflake object
$rawId = $id->id(); // Returns integer (e.g., 65898467809951744)
Snowflake class: Core functionality (e.g., toCarbon(), is()).HasSnowflakes trait: For Eloquent model integration.snowflake_id() helper: Convenience method for raw IDs.use Glhd\Bits\Database\HasSnowflakes;
class User extends Model
{
use HasSnowflakes; // Auto-generates Snowflake on create
protected $casts = [
'id' => Snowflake::class, // Casts DB integer to Snowflake object
];
}
HasSnowflakes for primary keys to avoid UUID/ULID overhead while maintaining sortability.Replace created_at comparisons with Snowflake IDs:
// Instead of:
User::where('created_at', '>', now()->subDays(7));
// Use:
User::where('id', '>', app(\Glhd\Bits\MakesSnowflakes::class)->firstForTimestamp(now()->subDays(7)));
Register the synthesizer in AppServiceProvider:
use Glhd\Bits\Support\Livewire\SnowflakeSynth;
public function boot(): void
{
Livewire::propertySynthesizer(SnowflakeSynth::class);
}
Extend Bits for non-Snowflake formats (e.g., Sonyflake):
use Glhd\Bits\Bits;
$sonyflake = Bits::sonyflake()->make();
BIGINT for Snowflake IDs (64-bit storage).Number precision issues).Snowflake::setTestNow() to mock timestamps:
Snowflake::setTestNow(now()->subHours(1));
Worker/Datacenter Limits:
BITS_WORKER_ID and BITS_DATACENTER_ID environment variables. For Lambda/Vapor, implement a locking mechanism (e.g., Redis) to avoid collisions.Epoch Mismatches:
BITS_EPOCH to a future date throws an exception.now()->subYears(5) for testing if time-traveling to the past.JavaScript Compatibility:
Number.MAX_SAFE_INTEGER (~52 bits).return response()->json(['id' => (string) $snowflake->id]);
Livewire Serialization:
Bits objects may not serialize properly.SnowflakeSynth (Snowflake) or BitsSynth (generic) in AppServiceProvider.$snowflake->is($other) to compare IDs.$snowflake->toCarbon() to verify time components.BITS_WORKER_ID/BITS_DATACENTER_ID.Custom Bit Formats:
$customBits = Bits::custom()
->timestampBits(35)
->workerBits(6)
->sequenceBits(10)
->make();
Sequence Resolvers:
$bits = Bits::snowflake()
->sequenceResolver(new \Glhd\Bits\Sequence\RedisSequenceResolver());
Blueprint Macros:
use Glhd\Bits\Support\BlueprintMacros;
BlueprintMacros::register();
// Now use `->whereSnowflakeGreaterThan()` in queries.
BITS_EPOCH is unset, defaults to 2023-01-01..env or config files to override defaults:
'bits' => [
'epoch' => '2020-01-01',
],
Carbon::setTestNow() (use Snowflake::setTestNow() instead).User::where('id', '>', $minId)->pluck('id'); // Faster than Snowflake objects
How can I help you explore Laravel packages today?