PHPackages                             bmilleare/sonyflake-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. bmilleare/sonyflake-php

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

bmilleare/sonyflake-php
=======================

A faithful PHP port of Sony's Sonyflake distributed unique-ID generator (v2).

v0.1.0(1mo ago)00MITPHPPHP ^8.2CI passing

Since May 28Pushed 1mo agoCompare

[ Source](https://github.com/bmilleare/sonyflake-php)[ Packagist](https://packagist.org/packages/bmilleare/sonyflake-php)[ RSS](/packages/bmilleare-sonyflake-php/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (1)Dependencies (3)Versions (2)Used By (0)

sonyflake-php
=============

[](#sonyflake-php)

A faithful PHP port of [Sony's Sonyflake](https://github.com/sony/sonyflake) v2 distributed unique-ID generator. Same algorithm, same defaults, same bit layout — produces byte-identical IDs to the Go reference for the same inputs.

[![CI](https://github.com/bmilleare/sonyflake-php/actions/workflows/ci.yml/badge.svg)](https://github.com/bmilleare/sonyflake-php/actions/workflows/ci.yml)[![Packagist](https://camo.githubusercontent.com/1762c86ec0abd009f27ee4e55ecc2d3f9d146a72fa426f79ff9bc6540837d59e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f626d696c6c656172652f736f6e79666c616b652d7068702e737667)](https://packagist.org/packages/bmilleare/sonyflake-php)[![PHP Version](https://camo.githubusercontent.com/7d527b2c2470f83caf61a3a4b4de0b697c7595dd0a3582caf3edc03d819a9ad7/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f626d696c6c656172652f736f6e79666c616b652d7068702e737667)](https://packagist.org/packages/bmilleare/sonyflake-php)[![License](https://camo.githubusercontent.com/516fadc9435126614160f2b8a54dbd55f3d942fe4fbea773e601258c6172e2e5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f626d696c6c656172652f736f6e79666c616b652d7068702e737667)](LICENSE)

What is Sonyflake?
------------------

[](#what-is-sonyflake)

Sonyflake is a Snowflake-family distributed ID generator that produces sortable 63-bit integer IDs. Its layout differs from Twitter's Snowflake to favour more machines over higher per-machine throughput, and to extend the lifetime to ~174 years:

```
[ time : 63 − BitsSequence − BitsMachineID bits ]
[ sequence : BitsSequence bits (default 8) ]
[ machine  : BitsMachineID bits (default 16) ]

```

Defaults match upstream v2: 39 bits of 10ms-resolution time, 8 bits of sequence (256 IDs per 10ms per generator), 16 bits of machine id (65 536 machines), start epoch `2025-01-01T00:00:00Z`.

Install
-------

[](#install)

```
composer require bmilleare/sonyflake-php
```

Requires PHP `^8.2`.

Quick start
-----------

[](#quick-start)

```
use Bmilleare\Sonyflake\Settings;
use Bmilleare\Sonyflake\Sonyflake;

$sf = new Sonyflake(new Settings(machineId: 1));

$id = $sf->nextId();           // e.g. 70368744177665
$parts = $sf->decompose($id);  // Decomposed { id, time, sequence, machine }
```

Two runnable example scripts ship in `examples/`:

```
php examples/basic.php    # explicit machine id, default v2 layout
php examples/leased.php   # two simulated FPM workers leasing distinct slots
```

⚠️ Machine IDs under PHP-FPM
----------------------------

[](#️--machine-ids-under-php-fpm)

Sonyflake has **no PID or entropy component** — uniqueness across processes rides entirely on each generator using a distinct 16-bit machine id. The Go-parity default (`PrivateIpResolver`, lower 16 bits of the host's private IPv4) gives every PHP-FPM worker on the same host the **same** id and will collide.

Under FPM (or any setup with multiple worker processes per host), use the shipped `LeasedResolver` with `FileLeaseStore`:

```
use Bmilleare\Sonyflake\MachineId\FileLeaseStore;
use Bmilleare\Sonyflake\MachineId\LeasedResolver;
use Bmilleare\Sonyflake\Settings;
use Bmilleare\Sonyflake\Sonyflake;

$resolver = new LeasedResolver(new FileLeaseStore('/var/run/sonyflake'));
$sf = new Sonyflake(new Settings(machineId: $resolver));
```

Each worker leases a distinct slot at boot, holds it for its lifetime (default TTL 1 hour, plus a live-PID check), and releases on exit via a shutdown hook.

Resolvers
---------

[](#resolvers)

ResolverUse when`PrivateIpResolver` (implicit default)One generator per host. **Not safe for FPM.**`EnvResolver`Orchestrator assigns each container/worker an env var (`SONYFLAKE_MACHINE_ID`).`LeasedResolver` + `FileLeaseStore`Multiple workers per host (PHP-FPM, Octane, queue workers).You can implement your own `LeaseStore` — Redis, APCu, etcd — by providing the three-method interface (`acquire`, `renew`, `release`):

```
use Bmilleare\Sonyflake\MachineId\Lease;
use Bmilleare\Sonyflake\MachineId\LeaseStore;

final class RedisLeaseStore implements LeaseStore
{
    public function acquire(int $maxId): Lease { /* atomic INCR with TTL */ }
    public function renew(Lease $lease): void { /* refresh TTL */ }
    public function release(Lease $lease): void { /* DEL */ }
}
```

Configuration
-------------

[](#configuration)

```
new Settings(
    startTime: new DateTimeImmutable('2025-01-01T00:00:00Z'),
    bitsSequence: 8,                       // 0..30
    bitsMachineId: 16,                     // 0..30; time = 63 − seq − machine ≥ 32
    timeUnitNanos: 10_000_000,             // 10 ms; min 1 ms
    machineId: $resolver,                  // int | MachineIdResolver | null (null → PrivateIpResolver)
    checkMachineId: fn (int $id) => true,  // optional validation
    clock: null,                           // null → SystemClock; inject for tests
);
```

Exceptions
----------

[](#exceptions)

All exceptions implement `Bmilleare\Sonyflake\Exception\SonyflakeException`:

ClassWhen`InvalidSettingsException`Bad bit widths, time unit, or start time in the future.`InvalidMachineIdException`Resolved machine id is out of range or rejected by `checkMachineId`.`OverTimeLimitException`Time bits exhausted (default config: ~174 years from start).`NoPrivateAddressException``PrivateIpResolver` found no private IPv4.`MachineIdExhaustedException`Every lease slot is held by a live worker.Go-parity notes
---------------

[](#go-parity-notes)

- `Sonyflake::nextId()` returns `int` (PHP signed 64-bit). The upstream Go v2 returns `int64`. Since only 63 bits are used, the value is always non-negative.
- `Sonyflake::decompose()` returns a typed `Decomposed` value object whose `toArray()` matches Go's map keys: `id`, `time`, `sequence`, `machine`.
- Default `StartTime` is **2025-01-01T00:00:00Z** (v2 default — v1 used 2014).
- Upstream's `sf.sequence` is initialised to the sequence mask (default 255), so the first `NextID()` call always wraps it to 0 in the else branch and bumps `elapsedTime` once. This port reproduces that behaviour exactly.
- Error sentinels (`ErrInvalidBitsTime`, `ErrOverTimeLimit`, …) map to the exception table above; see `InvalidSettingsException::*` named constructors for the granular settings cases.

Upstream parity verification
----------------------------

[](#upstream-parity-verification)

Parity isn't just claimed — it's tested against real IDs produced by the Go upstream. `tests/Parity/upstream/main.go` is a small program that imports `github.com/sony/sonyflake/v2`, runs `NextID()` across five configurations (default 8/16 layout, custom 4/8 layout, wider 8/20 layout, alternate machine ids, and a 1 ms time unit), and writes each id together with upstream's `Decompose()` output to a JSON fixture at `tests/Parity/upstream-vectors.json`.

`UpstreamParityTest.php` loads that fixture and asserts the PHP port's `Sonyflake::decompose()` returns the same `(time, sequence, machine)`tuples upstream produced for the same ids and `Settings`. The fixture is checked in, so CI does not need a Go toolchain.

To regenerate against a newer Sonyflake release:

```
cd tests/Parity/upstream
go run . > ../upstream-vectors.json
composer test
```

If `composer test` still passes after regenerating, the port is in sync with that release.

Testing your own code
---------------------

[](#testing-your-own-code)

Inject a `Bmilleare\Sonyflake\Clock\Clock` implementation that returns deterministic times and records sleeps. The package's own test suite uses exactly this pattern (`tests/Support/FakeClock.php`).

```
use Bmilleare\Sonyflake\Clock\Clock;

final class FrozenClock implements Clock
{
    public function __construct(private int $now) {}
    public function nowNanos(): int { return $this->now; }
    public function sleepNanos(int $nanos): void { $this->now += max(0, $nanos); }
}
```

License
-------

[](#license)

MIT. See [LICENSE](LICENSE).

Credits
-------

[](#credits)

Faithful port of [sony/sonyflake v2](https://github.com/sony/sonyflake) by Sony Group Corporation.

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance89

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity36

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

57d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/ed907bcb4cec221659478dc44dd9f88cd31b5d27546530002d85a40c72081b52?d=identicon)[bmilleare](/maintainers/bmilleare)

---

Top Contributors

[![bmilleare](https://avatars.githubusercontent.com/u/21267?v=4)](https://github.com/bmilleare "bmilleare (27 commits)")

---

Tags

unique-idsonyflakesnowflakeid-generatordistributed-id

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/bmilleare-sonyflake-php/health.svg)

```
[![Health](https://phpackages.com/badges/bmilleare-sonyflake-php/health.svg)](https://phpackages.com/packages/bmilleare-sonyflake-php)
```

###  Alternatives

[godruoyi/php-snowflake

An ID Generator for PHP based on Snowflake Algorithm (Twitter announced).

8652.6M70](/packages/godruoyi-php-snowflake)[kra8/laravel-snowflake

Snowflake for Laravel and Lumen.

192453.6k9](/packages/kra8-laravel-snowflake)[hyperf/snowflake

A snowflake library

27853.3k72](/packages/hyperf-snowflake)[infocyph/uid

UUID (RFC 9562), ULID, Snowflake ID, Sonyflake ID, and TBSL generator for PHP.

116.0k1](/packages/infocyph-uid)[identifier/identifier

Common Interfaces and Factories for Identifiers

3233.4k1](/packages/identifier-identifier)[ramsey/identifier

A PHP library for generating and working with identifiers, including UUIDs, ULIDs, and Snowflakes

606.9k2](/packages/ramsey-identifier)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
