PHPackages                             iliaal/lchash - 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. iliaal/lchash

ActivePhp-ext[Utility &amp; Helpers](/categories/utility)

iliaal/lchash
=============

Linear-probing hash table extension for PHP. Wraps glibc hsearch\_r where available, falls back to a small in-tree implementation everywhere else.

1.0.0(1mo ago)00PHP-3.01CPHP &gt;=7.4CI passing

Since Apr 28Pushed 3w agoCompare

[ Source](https://github.com/iliaal/lchash)[ Packagist](https://packagist.org/packages/iliaal/lchash)[ Docs](https://github.com/iliaal/lchash)[ RSS](/packages/iliaal-lchash/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)DependenciesVersions (2)Used By (0)

lchash
======

[](#lchash)

[![Tests](https://github.com/iliaal/lchash/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/iliaal/lchash/actions/workflows/tests.yml)[![Version](https://camo.githubusercontent.com/466ffd1efac53324cf3dbc567f474936f1596d0915e5bb65d49ff52726c755da/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f696c6961616c2f6c6368617368)](https://github.com/iliaal/lchash/releases)[![License: PHP-3.01](https://camo.githubusercontent.com/2d0c6e79d68e3ecde571be7a99c822e88c8379ff247dc40dddea7cad6872b8fb/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d5048502d2d332e30312d677265656e2e737667)](http://www.php.net/license/3_01.txt)[![Follow @iliaa](https://camo.githubusercontent.com/a54521c97521f05fbadec4bd9bcba96ff1eeaffe756a6d7338b47a628cdeb39b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466f6c6c6f772d40696c6961612d3030303030303f7374796c653d666c6174266c6f676f3d78266c6f676f436f6c6f723d7768697465)](https://x.com/intent/follow?screen_name=iliaa)

A small PHP extension exposing a string-keyed hash table backed by [klib khash](https://github.com/attractivechaos/klib). Two surface APIs: four procedural functions for a single per-request table (the original 2005 API), plus an `LcHash` class with `$obj[$key]` dimension access for multiple per-instance tables.

Supports PHP 7.4 through 8.5, both NTS and ZTS, on glibc Linux, musl, macOS, \*BSD, and Windows.

Originally released to PECL in 2005; this 1.0.0 line is a full modernization for the PHP 7.4+ era.

When to use this (and when not to)
----------------------------------

[](#when-to-use-this-and-when-not-to)

**Don't use it for raw speed.** PHP arrays remain faster on insert and lookup at every size we measured. The `bench/bench.php` script in this repo, run on a release build of PHP 8.4 NTS (glibc Linux x86\_64, -O2):

N entriesInsert (array)Insert (lchash proc)Insert (lchash OO)Lookup (array)Lookup (lchash proc)Lookup (lchash OO)Mem (array)Mem (lchash)10,0000.001s0.001s0.000s0.000s0.001s0.000s0.63 MB0.25 MB100,0000.007s0.014s0.009s0.002s0.009s0.005s5.00 MB2.03 MB1,000,0000.111s0.161s0.185s0.052s0.102s0.101s40.0 MB32.5 MBReproducible via `php -d extension=$(pwd)/modules/lchash.so bench/bench.php `.

Read it as: PHP arrays beat lchash by **1.4x to 1.7x on insert and 2x on lookup** at scale. The gap is structural: PHP's HashTable uses a packed bucket layout with inlined zvals and opcode-level array-access specialization that no extension can match.

The flip: **lchash uses less memory than PHP arrays at every size**(0.4x-0.8x), because keys and values are stored as refcount-shared zend\_strings with no per-entry Bucket overhead. At 10k entries lchash holds ~40% of the memory PHP arrays do; at 1M it's ~80%.

**Legitimate reasons to reach for lchash:**

- **Memory-tight workloads.** A long-running CLI worker holding hundreds of thousands of small string mappings will save real RAM vs. native arrays.
- **Porting C code.** If you have a C codebase using POSIX `hsearch_r` and want a near-1:1 PHP shim while migrating, the procedural API's "first writer wins" semantics line up exactly with glibc `hsearch(ENTER)`.
- **Legacy compatibility.** PECL has had this extension since 2005; some long-running codebases depend on the function names being stable. This release modernizes the implementation without changing the four-function surface.
- **Demonstration.** It's a small, focused, header-only-vendor-backed PECL extension that's a clean reading example for anyone learning PHP extension development.

For most code, use a PHP array.

Install
-------

[](#install)

### PIE (recommended on PHP 8.x)

[](#pie-recommended-on-php-8x)

[PIE](https://github.com/php/pie) is the PHP Foundation's PECL successor. It installs from Packagist, builds against the active `php-config`, and produces a loadable `.so` / `.dll`.

```
pie install iliaal/lchash
```

Then add `extension=lchash` to your `php.ini`.

### PECL

[](#pecl)

The package remains in the PECL channel for legacy installers:

```
pecl install lchash
```

### From source

[](#from-source)

```
phpize
./configure --enable-lchash
make
make install
```

### Windows

[](#windows)

Pre-built `.dll` zips are attached to every [release](https://github.com/iliaal/lchash/releases), covering PHP 8.3 / 8.4 / 8.5 × x64 / x86 × NTS / TS. Download the matching zip, extract `php_lchash.dll` into your `ext/` directory, and add `extension=lchash` to `php.ini`.

API
---

[](#api)

### Procedural (single per-request table)

[](#procedural-single-per-request-table)

```
lchash_create(int $n_entries): bool
lchash_destroy(): bool
lchash_insert(string $key, string $value): bool
lchash_find(string $key): string|false
```

### Object-oriented (multiple per-instance tables)

[](#object-oriented-multiple-per-instance-tables)

```
$lc = new LcHash(int $n_entries = 1048576);
$lc[$key] = $value;       // write_dimension, last writer wins
$value = $lc[$key];       // read_dimension, returns null on miss
isset($lc[$key]);         // has_dimension
unset($lc[$key]);         // unset_dimension
```

### Semantics

[](#semantics)

- **Procedural:** one table per request. Calling `lchash_create()`twice without an intervening `lchash_destroy()` returns `false`and emits a warning. The table is destroyed at request shutdown if userland forgets to call `lchash_destroy()`.
- **OO:** one table per `LcHash` instance, allocated lazily on first write. Destroyed when the object is freed.
- `n_entries` is capped at 1,048,576 (`1
