Skip to content

Big Integers

Daniel Carbone edited this page Nov 6, 2026 · 1 revision

Big Integers

Consul uses Go uint64 for indexes, flags, and some counters. PHP's int is a signed 64-bit integer, so values above PHP_INT_MAX (9223372036854775807) would overflow. As of v3.1.0, every uint64 field is a Brick\Math\BigInteger.

Affected fields

Some common examples:

  • CreateIndex, ModifyIndex, LockIndex on most models
  • KV\KVPair::$Flags
  • QueryMeta::$LastIndex, QueryOptions::$WaitIndex
  • KVPair CAS indexes (ModifyIndex passed to KV->CAS() / DeleteCAS())
  • Raft indexes and terms (Operator\RaftServer, autopilot health, etc.)
  • Event\UserEvent::$LTime and the return value of Event->IDToIndex()

If a field is uint64 in the Go client, it is a BigInteger here.

Setting values

Constructors and setters accept any of:

  • a non-negative int
  • a numeric string (an optional leading + is allowed)
  • a BigInteger
use DCarbone\PHPConsulAPI\KV\KVPair;

new KVPair(Key: 'a', Flags: 42);
new KVPair(Key: 'a', Flags: '18446744073709551615');
new KVPair(Key: 'a', Flags: \Brick\Math\BigInteger::of(42));

Strings are validated with BigInteger::parse() (as recommended for untrusted input) and a maximum of 20 digits. Anything else throws \InvalidArgumentException:

Input Result
-1 -1 is outside the uint64 range
'18446744073709551616' 18446744073709551616 is outside the uint64 range
'1.5', 'abc', ' 5', '0x10' "..." is not a valid uint64 value

The same conversion is available as a function:

use function DCarbone\PHPConsulAPI\PHPLib\uint64;

$idx = uint64('12345'); // BigInteger

Reading values

Use the BigInteger API instead of PHP integer operators:

if ($pair->Flags->isEqualTo(42)) { /* ... */ }
if ($qm->LastIndex->isGreaterThan($lastSeen)) { /* ... */ }

$next  = $qm->LastIndex->plus(1);
$asStr = (string)$qm->LastIndex;
$asInt = $pair->Flags->toInt(); // throws Brick\Math\Exception\IntegerOverflowException if > PHP_INT_MAX

== and === against an int won't work: a BigInteger is an object.

Pass QueryMeta::$LastIndex straight back as WaitIndex for blocking queries. You don't need to convert it:

[$pairs, $qm, $err] = $consul->KV->List(prefix: 'app/');
[$pairs, $qm, $err] = $consul->KV->List(
    prefix: 'app/',
    opts: new QueryOptions(WaitIndex: $qm->LastIndex, WaitTime: '5m'),
);

JSON

Responses are always decoded with JSON_BIGINT_AS_STRING, so large numbers reach the models as strings and are never truncated to floats.

json_encode() writes BigInteger values as strings, because BigInteger::jsonSerialize() returns a string. Consul's API expects numbers. The library uses encode_json() internally for request bodies, and you can use it too:

use function DCarbone\PHPConsulAPI\PHPLib\encode_json;

json_encode(['f' => $pair->Flags]); // {"f":"18446744073709551615"}
encode_json(['f' => $pair->Flags]); // {"f":18446744073709551615}

encode_json(value, flags, depth) accepts the same flags as json_encode() and throws \JsonException on failure.

Upgrading from v3.0

Code that did arithmetic or comparisons on these fields needs updating:

// before
if ($pair->ModifyIndex > $last) { $last = $pair->ModifyIndex; }

// after
if ($pair->ModifyIndex->isGreaterThan($last)) { $last = $pair->ModifyIndex; }

Setters still accept plain ints, so most write-side code is unchanged.

Clone this wiki locally