PHPackages                             k-kinzal/ztd-query-mysqli-adapter - 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. k-kinzal/ztd-query-mysqli-adapter

ActiveLibrary

k-kinzal/ztd-query-mysqli-adapter
=================================

MySQLi adapter for ZTD Query

v0.1.1(2mo ago)016↓100%MITPHPPHP ^8.1

Since Mar 6Pushed 2mo agoCompare

[ Source](https://github.com/k-kinzal/ztd-query-mysqli-adapter)[ Packagist](https://packagist.org/packages/k-kinzal/ztd-query-mysqli-adapter)[ RSS](/packages/k-kinzal-ztd-query-mysqli-adapter/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (12)Versions (3)Used By (0)

ZTD Query MySQLi Adapter
========================

[](#ztd-query-mysqli-adapter)

[![License: MIT](https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667)](https://opensource.org/licenses/MIT)[![PHP Version](https://camo.githubusercontent.com/7535257ca228724c93658bd52583d4e47a9bab02c356abf6e54c1d575f2151e6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e312532422d626c75652e737667)](https://www.php.net/)

MySQLi adapter for [ZTD Query PHP](https://github.com/k-kinzal/ztd-query-core). Drop-in replacement for mysqli that transparently applies Zero Table Dependency query transformation.

Overview
--------

[](#overview)

This package provides `ZtdMysqli` and `ZtdMysqliStatement`, which extend `mysqli` and `mysqli_stmt` respectively. They intercept SQL queries and transform them using CTE (Common Table Expression) shadowing, enabling SQL unit testing without modifying physical databases.

- **Drop-in replacement** - `ZtdMysqli` extends `mysqli` and is type-compatible everywhere `mysqli` is expected
- **Transparent rewriting** - All queries are automatically rewritten at `prepare()`/`query()`/`execute_query()` time
- **Toggle on/off** - Enable or disable ZTD mode at runtime with `enableZtd()`/`disableZtd()`
- **Wrap existing connections** - Use `ZtdMysqli::fromMysqli()` to wrap an existing mysqli instance without creating a new connection

Requirements
------------

[](#requirements)

- PHP 8.1 or higher
- MySQLi extension
- MySQL 5.6 - 9.1
- [k-kinzal/ztd-query-php](https://github.com/k-kinzal/ztd-query-core) (core)
- [k-kinzal/ztd-query-mysql](https://github.com/k-kinzal/ztd-query-mysql) (MySQL platform)

Installation
------------

[](#installation)

```
composer require --dev k-kinzal/ztd-query-mysqli-adapter
```

Usage
-----

[](#usage)

### Creating a New Connection

[](#creating-a-new-connection)

```
use ZtdQuery\Adapter\Mysqli\ZtdMysqli;

$mysqli = new ZtdMysqli('localhost', 'user', 'password', 'test');

// Define schema and insert fixture data
$mysqli->query('CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255), email VARCHAR(255))');
$mysqli->query("INSERT INTO users (id, name, email) VALUES (1, 'Alice', 'alice@example.com')");
$mysqli->query("INSERT INTO users (id, name, email) VALUES (2, 'Bob', 'bob@example.com')");

// Query against fixture data (no physical table access)
$stmt = $mysqli->prepare('SELECT * FROM users WHERE id = ?');
$stmt->bind_param('i', $id);
$id = 1;
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
// ['id' => 1, 'name' => 'Alice', 'email' => 'alice@example.com']
```

### Wrapping an Existing mysqli Instance

[](#wrapping-an-existing-mysqli-instance)

```
use ZtdQuery\Adapter\Mysqli\ZtdMysqli;

$existingMysqli = new mysqli('localhost', 'user', 'password', 'test');
$ztdMysqli = ZtdMysqli::fromMysqli($existingMysqli);
```

### Testing Write Operations

[](#testing-write-operations)

INSERT/UPDATE/DELETE statements are converted to SELECT queries that return the affected rows:

```
$mysqli->query('CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255))');
$mysqli->query("INSERT INTO users (id, name) VALUES (1, 'Alice')");

// INSERT returns the inserted row data
$result = $mysqli->query("INSERT INTO users (id, name) VALUES (2, 'Bob')");
$row = $result->fetch_assoc();
// ['id' => 2, 'name' => 'Bob']

// UPDATE returns the updated row data
$result = $mysqli->query("UPDATE users SET name = 'Alice Updated' WHERE id = 1");
$row = $result->fetch_assoc();
// ['id' => 1, 'name' => 'Alice Updated']

// DELETE returns the deleted row data
$result = $mysqli->query("DELETE FROM users WHERE id = 1");
$row = $result->fetch_assoc();
// ['id' => 1, 'name' => 'Alice']
```

### Enabling/Disabling ZTD Mode

[](#enablingdisabling-ztd-mode)

```
$mysqli = new ZtdMysqli('localhost', 'user', 'password', 'test');

// Disable ZTD to execute against physical database
$mysqli->disableZtd();
$mysqli->query('CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255))');

// Re-enable ZTD for testing
$mysqli->enableZtd();

// Check current status
$mysqli->isZtdEnabled(); // true
```

### Affected Row Count

[](#affected-row-count)

Due to PHP's C extension property handler, `$mysqli->affected_rows` may not work reliably with ZTD operations. Use the dedicated method instead:

```
$mysqli->query("INSERT INTO users (id, name) VALUES (1, 'Alice')");
$affectedRows = $mysqli->lastAffectedRows();
// 1
```

### Configuration

[](#configuration)

```
use ZtdQuery\Adapter\Mysqli\ZtdMysqli;
use ZtdQuery\Config\ZtdConfig;
use ZtdQuery\Config\UnsupportedSqlBehavior;
use ZtdQuery\Config\UnknownSchemaBehavior;

$config = new ZtdConfig(
    unsupportedBehavior: UnsupportedSqlBehavior::Exception,
    unknownSchemaBehavior: UnknownSchemaBehavior::Exception,
    behaviorRules: [
        'BEGIN' => UnsupportedSqlBehavior::Ignore,
        'COMMIT' => UnsupportedSqlBehavior::Ignore,
        'ROLLBACK' => UnsupportedSqlBehavior::Ignore,
    ],
);

$mysqli = new ZtdMysqli('localhost', 'user', 'password', 'test', config: $config);
```

OptionValuesDescription`unsupportedBehavior``Ignore`, `Notice`, `Exception`Default behavior when unsupported SQL is executed`unknownSchemaBehavior``Passthrough`, `Exception`Behavior when unknown table is referenced`behaviorRules``array`Per-pattern behavior overrides (first match wins)API Reference
-------------

[](#api-reference)

### ZtdMysqli

[](#ztdmysqli)

MethodDescription`__construct($hostname, $username, $password, $database, $port, $socket, $config)`Create a new ZTD-wrapped mysqli connection`ZtdMysqli::fromMysqli($mysqli, $config)`Wrap an existing mysqli instance`enableZtd()`Enable ZTD mode`disableZtd()`Disable ZTD mode`isZtdEnabled()`Check whether ZTD mode is enabled`lastAffectedRows()`Get affected row count from the last ZTD or regular operation`prepare($query)`Prepare a statement (rewritten if ZTD enabled)`query($query, $resultMode)`Execute a query with ZTD processing`real_query($query)`Execute a query without fetching results`execute_query($query, $params)`Execute a parameterized query (PHP 8.2+)All other mysqli methods (`begin_transaction`, `commit`, `rollback`, `real_escape_string`, etc.) are delegated to the inner mysqli instance. Properties are delegated via `__get`/`__isset`.

### ZtdMysqliStatement

[](#ztdmysqlistatement)

Extends `mysqli_stmt` with ZTD-aware behavior. `execute()`, `get_result()`, and `bind_param()` work transparently. Use `ztdAffectedRows()` to get the ZTD-aware affected row count for write operations.

Development
-----------

[](#development)

```
# Run unit tests
composer test:unit

# Run integration tests (requires Docker)
composer test:integration

# Run all tests
composer test

# Run linter (PHP-CS-Fixer + PHPStan level max)
composer lint

# Fix code style
composer format
```

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for details.

###  Health Score

35

—

LowBetter than 79% of packages

Maintenance86

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity33

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

67d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/4458a22db62c885006248e08715301bcb73e78c1057e2bbf686af001729165d5?d=identicon)[kinzal](/maintainers/kinzal)

---

Top Contributors

[![k-kinzal](https://avatars.githubusercontent.com/u/1281825?v=4)](https://github.com/k-kinzal "k-kinzal (5 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/k-kinzal-ztd-query-mysqli-adapter/health.svg)

```
[![Health](https://phpackages.com/badges/k-kinzal-ztd-query-mysqli-adapter/health.svg)](https://phpackages.com/packages/k-kinzal-ztd-query-mysqli-adapter)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
