Judy 2.5.0

PHP Judy implements sparse dynamic arrays (aka Judy Arrays)


PHP Judy implements sparse dynamic arrays (aka Judy Arrays). This extension is based
on the Judy C library. A Judy array consumes memory only when it is populated,
yet can grow to take advantage of all available memory if desired. Judy's key benefits
are scalability, high performance, and memory efficiency.

License: PHP

Changes

- BC BREAK: a negative integer offset now stores that key instead of appending.
Integer keys are unsigned machine words, so $j[-1] = $v addresses the maximum
index and reads back as -1. Previously every key in [PHP_INT_MIN, -1] was
discarded and the value appended at the next free index, so isset($j[-1]) was
false immediately after the write. See MIGRATION_2.5.0.md.
- BC BREAK: $j[] = $v now throws when the maximum index is occupied, instead of
wrapping onto index 0 and overwriting it.
- FIX: $j[] = $v no longer loses a value after a negative-offset write left the
append watermark stale
- FIX: map()/filter() preserve negative keys instead of relocating them
- SECURITY: fix use-after-free write on *_TO_MIXED overwrite/unset when a stored
value's destructor re-enters and mutates the same array (write-before-dtor /
delete-before-free)
- SECURITY: fix type confusion (UB) in getAll()/next()/rewind() for adaptive
types, which queried a JudyHS operation against the JudyL (SSO) store
- FIX: add get_gc handler so reference cycles through MIXED values are collectable
(previously leaked until request shutdown)
- FIX: STRING_TO_*_ADAPTIVE counter no longer double-counts when the value 0 is
re-stored (size/count/equals/averageValues were affected)
- FIX: $j[] = append after clone/fromArray/putAll no longer overwrites index 0
- FIX: first()/last()/searchNext()/prev() now work on adaptive types
- FIX: fromArray()/putAll() reject non-integer keys on integer-keyed types instead
of inserting at the string's hash
- FIX: __unserialize() on a populated object frees prior contents (no leak)
- FIX: forEach()/filter()/map() callbacks may re-enter without corrupting iteration
- FIX: equals() on INT_TO_PACKED no longer risks an infinite loop
- FIX: allocation failure (JERR) during write/unset is reported as failure, not success
- FIX: bulk operations stop on the first thrown key instead of continuing with a
pending exception; clone/slice no longer leak zvals or diverge on OOM paths
- FEATURE: keys(), values() and toArray() take an inclusive [$start, $end] key
range, where null leaves that side unbounded. All key types; string-keyed types
require string bounds and compare them lexicographically. A bounded read is one
traversal writing straight into the PHP array — prefer it to slice($lo,
$hi)->keys(), which copies a whole sub-array first.
- FEATURE: size($start, $end) counts that same range, including on the six
string-keyed types, without materialising anything. Previously it accepted
string bounds, ignored them, and returned the whole-array count. Its parameters
were renamed $index_start/$index_end -> $start/$end to match the other range
methods, which breaks named-argument callers only; its defaults moved from
(0, -1) to (null, null). populationCount() is unchanged and stays
integer-keyed-only — it answers from libJudy's O(1) population cache, which the
string-keyed stores lack. See MIGRATION_2.5.0.md.
- FEATURE: new Judy($type, optimizeIteration: true) mirrors payloads into the key
index for 24-47% faster ordered reads, at a write-path and memory cost. Opt-in,
per-instance, off by default, and honoured only by STRING_TO_INT_HASH and
STRING_TO_INT_ADAPTIVE; isIterationOptimized() reports what took effect.
- FEATURE: Judy instances are now legible to debuggers — var_dump()/print_r()
show type, count, memory usage, first/last key and a bounded element preview
(judy.debug_preview_size). Ships lldb/gdb pretty-printers for the extension's
own structs under scripts/.
- FEATURE: set operations (intersect/diff/xor) now supported for STRING_TO_INT_ADAPTIVE
- BUILD: extension compiles warning-free; CI now fails on any new compiler warning
- BUILD: minimum PHP raised to 8.1 (PHP 8.0 is no longer tested in CI)