npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

php-polycall

v1.1.0

Published

PHP FFI binding for the Polycall binding ABI v1 (libpolycall >= 1.1.0): config validation, RPC calls and peer nodes

Readme

php-polycall

PHP FFI binding for the Polycall core's binding ABI v1 (polycall.h, libpolycall >= 1.1.0): configuration validation, polycall_rpc calls and peer-to-peer nodes, from PHP through ext-ffi. Composer package obinexus/php-polycall; npm distribution php-polycall (not yet published).

The binding declares the exact C signatures from polycall.h (Polycall::C_DEFINITION) and resolves every symbol when the library is loaded. Configuration parsing, the wire protocols and the peer transport all stay in the core.

Requirements

  • PHP >= 8.1 with ext-ffi (the CLI's default ffi.enable=preload allows FFI from CLI scripts; set ffi.enable=1 for other SAPIs)
  • the Polycall core >= 1.1.0 installed (libpolycall.so.1, polycall.dll / libpolycall.dll, or libpolycall.1.dylib)

QA status: tested on Linux x86_64 (Docker php:8.3-cli NTS and php:8.3-zts with ext-parallel) against the real core. The Windows (polycall.dll / libpolycall.dll) and macOS loader paths are implemented but have not been run in QA yet (no PHP on the Windows QA host, no macOS host).

Loading the library

new Polycall() tries, in order:

  1. POLYCALL_LIBRARY (an explicit file path; a path that does not exist is an error, not a fallback),
  2. the platform name through the OS loader search path: polycall.dll then libpolycall.dll (Windows), libpolycall.so.1 (Linux, via LD_LIBRARY_PATH / ldconfig), libpolycall.1.dylib (macOS).

No package or parent directory is searched. A missing library, a library without the ABI v1 symbols (a 1.0 core) or polycall_ffi_abi_version() != 1 raises LibraryException naming the library and the problem.

API

use OBINexus\Polycall\Polycall;
use OBINexus\Polycall\PolycallException;

$pc = new Polycall();                      // or new Polycall('/path/to/libpolycall.so.1')
$pc->abiVersion();                         // 1
$pc->version();                            // "1.1.0"

// configuration: the documented entry point, polycall_ffi_run_config(path, 1)
$status = $pc->runConfig('php-polycallrc');          // 0 = POLYCALL_OK, raw status otherwise
$pc->runConfig('php-polycallrc', false);              // run=0: validate, unknown keys are warnings
$pc->runConfigOrThrow('php-polycallrc');              // throws PolycallException
$json = $pc->describe('php-polycallrc');

// one polycall_rpc round trip to `polycall start` / `polycall daemon start`
$out = $pc->call('127.0.0.1:8084', 'inventory', 'get', '{"item_id":"widget-a"}', 2000);

// peer nodes
$alpha = $pc->openPeer('alpha', '127.0.0.1:0', getenv('POLYCALL_DEV_TOKEN') ?: null);
$alpha->register('beta', '127.0.0.1:9002');
$alpha->send('beta', "binary\0safe", 'msg-1', 5000);
$message = $alpha->recv(5000);             // Message {sender, messageId, payload}
$alpha->ping('beta');
$alpha->list();  $alpha->health();  $alpha->endpoint();  $alpha->nodeId();
$alpha->unregister('beta');  $alpha->cancel();  $alpha->close();

Every failure throws PolycallException: status() / getCode() is the POLYCALL_E_* code (constants in Status), statusName() and statusText() come from polycall_strerror, detail() is polycall_last_error, and output() holds the remote error object of a failed call(). recv() with a too-small capacity throws POLYCALL_E_TOO_LARGE, reports the needed size in output() and leaves the message queued.

Arguments are checked before they reach C (PHP FFI would otherwise wrap or truncate them silently): timeouts must be in 0..Polycall::WAIT_FOREVER (-1 used to become "wait forever"), a recv() capacity must be >= 0 (a capacity above the 1 MiB message limit is clamped, never allocated), handles must fit int32, and text arguments (paths, ids, endpoints, JSON, tokens) must not contain NUL bytes. Violations throw PolycallException with POLYCALL_E_INVALID_ARGUMENT / POLYCALL_E_INVALID_HANDLE; this includes runConfig() with a NUL in the path. Payloads stay binary-safe.

Ownership: a Peer from openPeer() owns its node and closes it once — on close() or when the object is destroyed. Peer::fromHandle() wraps a handle owned elsewhere (another Polycall instance or thread) and never closes it on destruction.

Threads: an NTS PHP has no threads, so nothing in the process can call cancel() / close() while recv() blocks; use bounded recv() timeouts there. On a thread-safe (ZTS) PHP with ext-parallel, another thread can create its own Polycall (same library, same process-wide handles) and wake a blocked recv() with Peer::fromHandle($pc, $handle)->cancel() or ->close(); this is tested.

Tests

tests/run-real-core.sh runs the PHPUnit suite (tests/RealCore) against the real installed core: library/ABI checks, loader failures (missing library, an old core without ABI v1 symbols, ABI 2), run_config, call against a live polycall start runtime, two peer nodes exchanging payloads both ways (empty, UTF-8, binary with NUL, exactly 1 MiB, 1 MiB + 1), registry ownership, de-duplication, auth, dead peers, timeouts, small buffers, handle lifecycle, concurrent senders, argument bounds, a non-ASCII config path, and interop with a C node run by polycall peer serve / send / recv. On a ZTS PHP with ext-parallel it also runs the threads group: cancel / close waking a recv() blocked in another thread, threaded senders on one handle, concurrent calls. A missing PHP, ext-ffi, PHPUnit or core is reported as SKIP (exit 77), never as success; a skipped test fails the run.

composer install
sh tests/run-real-core.sh            # core in /opt/polycall, or set POLYCALL_PREFIX / POLYCALL_LIBRARY

tests/interop/exchange.php is the cross-language exchange script used with the Ruby binding's tests/interop/exchange.rb. npm test runs the package metadata test and then the real-core suite.

Author and license

Nnamdi Michael Okpala ([email protected]). MIT, see LICENSE.