PHP deployment gets difficult when a Composer dependency quietly becomes an operating-system dependency, because the package then needs the right compiler, headers, extension ABI, libc, architecture, and permission to edit a production php.ini; the MongrelDB PHP client avoids that custom-extension path, installs through Composer, and talks to mongreldb-server over HTTP, while being precise about the two standard extensions it still requires: ext-curl and ext-json.
“Pure PHP” here means the client itself contains PHP source and does not ship a MongrelDB .so, invoke phpize, or bind the Rust engine into the PHP process. It does not mean a bare PHP binary with every extension disabled. The current package requires PHP 8.4 or newer, cURL, JSON, Composer, and a reachable MongrelDB daemon.
Install
composer require visorcraft/mongreldb-php
Then connect through the public Database class:
<?php
require __DIR__ . '/vendor/autoload.php';
use Visorcraft\MongrelDB\Database;
$db = new Database(
'http://127.0.0.1:8453',
token: getenv('MONGRELDB_TOKEN')
);
$rows = $db->sql(
'SELECT id, status FROM orders WHERE status = $1 LIMIT 20',
['paid']
);
The package name, class name, server port, and authentication options match the current client repository. An older version of this article showed a Client constructor that is not the public quick-start API; existing URLs are preserved, but examples should follow the package rather than the article date.
What the package covers
The PHP client exposes typed CRUD, batch transactions with idempotency keys, native query conditions, SQL, schema management, authentication administration, stored procedures, and compaction. HTTP failures map into typed exceptions such as AuthException, NotFoundException, ConstraintException, ConnectionException, and QueryException instead of forcing every caller to switch on a status code.
A batch transaction stages operations in the client and sends them for one atomic server commit:
$txn = $db->beginTransaction();
$txn->put('orders', [1 => 20, 2 => 'alice@example.com', 3 => 100.00]);
$txn->put('orders', [1 => 21, 2 => 'bob@example.com', 3 => 75.00]);
$txn->commit(idempotencyKey: 'orders-import-2026-08-02');
An idempotency key lets a retry receive the original committed response when the first HTTP response disappeared after the server completed the transaction. It does not make an arbitrary sequence of separate requests atomic; the operations have to belong to the same batch commit.
cURL is the default transport
ext-curl is a Composer requirement and the default transport. The package reuses request handles within the PHP process. PHP 8.5 can opt into persistent cURL share handles for DNS, TLS-session, and connection data across request lifetimes:
$db = new Database(
'http://127.0.0.1:8453',
persistentSharing: true
);
That option is off by default and degrades to per-request pooling on PHP 8.4. Cookie data is deliberately excluded from persistent sharing because carrying authenticated cookies between unrelated requests would cross a security boundary.
The repository also includes a stream transport and a transport interface for custom adapters, but ext-curl remains a declared installation dependency in the current Composer package. A fallback implementation in the source tree is not the same as permission to omit the dependency from production images.
Why HTTP is a reasonable PHP boundary
PHP-FPM already treats application work as requests handled by a process pool. A language-native HTTP client fits that deployment model, crosses ordinary TLS and proxy infrastructure, and keeps the Rust engine inside one daemon instead of compiling it into every FPM image.
The trade is latency and service ownership. The current MongrelDB qualification fixture measured a warm loopback SQL point query at 1.287 milliseconds p50, 2.070 milliseconds p95, and 2.396 milliseconds p99 on the documented benchmark host. That path includes HTTP handling, session lookup, SQL planning, execution, and JSON serialization, so it is not a pure cURL overhead number and should not be described as a few hundred microseconds of framing.
Use useful transaction and result batches rather than one HTTP call per cell. The daemon must be started, monitored, upgraded, authenticated, and backed up; installing the PHP client through Composer does not make the database itself serverless.
What this mode cannot do
The PHP package does not embed the database engine and cannot open a MongrelDB directory directly. It cannot work while mongreldb-server is unreachable, and it does not avoid network timeout ambiguity: a client can lose the response after the server committed. Idempotency keys are the tool for retrying state-changing requests whose outcome is uncertain.
It also does not make arbitrary SQL injection-safe. Values belong in bound parameters, identifiers and permission names need the package’s validated APIs, and credentials belong in environment or secret storage rather than source files.
For PHP applications that can operate one local or remote daemon, those limits buy a simple package lifecycle: Composer updates PHP source while the server owns the native engine and database files. For a process that must carry its database in-process, use one of the nine embedded language bindings instead.
Source, current requirements, and runnable examples live in the MongrelDB PHP client repository.