techone/database

PDO database library

Maintainers

Package info

github.com/leeqvip/database

pkg:composer/techone/database

Transparency log

Statistics

Installs: 54 074

Dependents: 0

Suggesters: 0

Stars: 4

Open Issues: 0

v2.1.0 2026-08-30 07:03 UTC

This package is auto-updated.

Last update: 2026-08-30 07:05:15 UTC


README

PHPUnit Coverage Status Latest Stable Version Total Downloads License

A lightweight PDO database library for PHP.

The currently supported databases are:

type database PDO driver
mysql MySQL pdo_mysql
pgsql PostgreSQL pdo_pgsql
sqlite SQLite pdo_sqlite
sqlsrv SQL Server pdo_sqlsrv

Requirements

  • PHP >= 8.0
  • ext-pdo
  • The PDO driver for your database, e.g. pdo_mysql, pdo_pgsql or pdo_sqlite. For SQL Server, install the pdo_sqlsrv extension (not bundled with PHP).

Installation

Use Composer

composer require leeqvip/database

Usage

Quick start

require_once './vendor/autoload.php';

use Leeqvip\Database\Manager;

$config = [
    'type'     => 'mysql', // mysql, pgsql, sqlite, sqlsrv
    'hostname' => '127.0.0.1',
    'database' => 'test',
    'username' => 'root',
    'password' => 'abc-123',
    'hostport' => '3306',
    'charset'  => 'utf8mb4',
];

$manager = new Manager($config);
$connection = $manager->getConnection(); // lazily creates and caches one Connection

// Returns all matching rows as an array of associative arrays
$rows = $connection->query('SELECT * FROM `users` WHERE `id` = :id', ['id' => 1]);

// Returns the number of affected rows
$count = $connection->execute(
    'UPDATE `users` SET `name` = :name WHERE `id` = :id',
    ['name' => 'joker', 'id' => 1]
);

Both named parameters and positional placeholders are supported. Numeric keys in the bind array are converted to 1-based positional parameters:

$rows = $connection->query('SELECT * FROM `users` WHERE `id` = ?', [1]);

Configuration

Only type is required; everything else has a sensible default.

key description default
type Connector name: mysql, pgsql, sqlite, sqlsrv (required)
hostname Server host 127.0.0.1
hostport Server port 3306
database Database name. For SQLite, the path to the database file ''
username Username ''
password Password ''
charset MySQL connection charset
socket MySQL unix socket; takes precedence over hostname/hostport
dsn Full DSN string; bypasses the auto-generated DSN
params PDO attributes, merged over the defaults below

The default PDO attributes (MySQL and SQLite) are:

[
    PDO::ATTR_CASE              => PDO::CASE_NATURAL,
    PDO::ATTR_ERRMODE           => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_ORACLE_NULLS      => PDO::NULL_NATURAL,
    PDO::ATTR_STRINGIFY_FETCHES => false,
    PDO::ATTR_EMULATE_PREPARES  => false,
]

Note that PDO::ATTR_EMULATE_PREPARES is disabled by default, so queries use native prepared statements where the driver supports them. (The pgsql and sqlsrv connectors use the same defaults minus PDO::ATTR_EMULATE_PREPARES.)

SQLite

SQLite only needs the path to the database file:

$connection = (new Manager([
    'type'     => 'sqlite',
    'database' => '/path/to/database.sqlite',
]))->getConnection();

Custom DSN

If the auto-generated DSN is not enough, pass a complete one and it will be used as-is:

$config = [
    'type'     => 'mysql',
    'dsn'      => 'mysql:unix_socket=/tmp/mysql.sock;dbname=test;charset=utf8mb4',
    'username' => 'root',
    'password' => 'abc-123',
];

Raw PDO access

$pdo = $connection->getPdo(); // lazily connects on first access
$connection->connect();       // or connect explicitly

$statement = $connection->getPdo()->prepare('SELECT VERSION()');
$statement->execute();

You may also skip the Manager entirely and use Leeqvip\Database\Connection directly with the same config array.

Transactions

$connection->beginTransaction();
try {
    $connection->execute(
        'UPDATE `accounts` SET `balance` = `balance` - :amount WHERE `id` = :id',
        ['amount' => 100, 'id' => 1]
    );
    $connection->execute(
        'UPDATE `accounts` SET `balance` = `balance` + :amount WHERE `id` = :id',
        ['amount' => 100, 'id' => 2]
    );
    $connection->commit();
} catch (\Throwable $e) {
    $connection->rollBack();
    throw $e;
}

Or use the transaction() helper, which commits automatically when the callback returns and rolls back and re-throws when it throws. The callback receives the connection:

use Leeqvip\Database\Connection;

$balance = $connection->transaction(function (Connection $db) {
    $db->execute(
        'UPDATE `accounts` SET `balance` = `balance` - :amount WHERE `id` = :id',
        ['amount' => 100, 'id' => 1]
    );
    return $db->query('SELECT `balance` FROM `accounts` WHERE `id` = :id', ['id' => 1])[0]['balance'];
});

Transactions can be nested. The inner ones are simulated with savepoints, so an inner rollBack() only undoes its own work and leaves the outer transaction intact. This also applies to transaction() calls inside a transaction() callback.

Two things to be aware of:

  • Don't call commit() or rollBack() manually inside a transaction() callback. If the callback rolls back and then returns, transaction() throws a LogicException when it tries to commit; and anything the callback already committed manually cannot be undone by an outer rollBack().
  • Some statements end the transaction implicitly, e.g. DDL statements like ALTER TABLE commit on MySQL. The library does not detect this; instead its internal level is reset after every commit() / rollBack(), so it never gets stuck and the database reports the mismatch on the next statement that needs a transaction.

Exceptions

  • A missing type or an unknown connector throws InvalidArgumentException when the connection object is created (i.e. in getConnection()).
  • Calling commit() or rollBack() without an active transaction throws LogicException.
  • Connection and query failures throw PDOException.

Testing

composer install
vendor/bin/phpunit

License

This project is licensed under the Apache 2.0 license.