Oihana PHP

PDOTrait uses trait:short, trait:short, \oihana\traits\ContainerTrait, trait:short, trait:short

Adds a complete PDO data-access layer to any model: prepared-statement execution, named-parameter binding, schema-aware result mapping and several `fetch*` strategies (single row, full array, streaming generator, single column, column list).

Key behaviours:

  • Safe binding: PDOTrait::bindValues() maps an associative array onto :name placeholders, with optional per-value PDO type hints (['id' => [5, PDO::PARAM_INT]]).
  • Schema mapping: when a $schema class is set, statements use PDO::FETCH_CLASS (optionally combined with PDO::FETCH_PROPS_LATE when $deferAssignment is true); otherwise rows fall back to PDO::FETCH_ASSOC and are returned as stdClass/arrays.
  • Post-fetch alteration: every fetched row passes through AlterDocumentTrait::alter(), so registered property alterations are applied transparently.
  • Resilient by default: each fetch* method swallows exceptions and logs a warning, returning a neutral value (null / []). Pass $throwable = true to rethrow instead, e.g. inside transactions where failures must propagate.
  • DI integration: the PDO instance is resolved through PDOTrait::initializePDO(), either directly or from a PSR-11 container by service id.

Requires the following traits to be mixed into the host class:

Tags
author

Marc Alcaraz (ekameleon)

since
1.0.0

Table of Contents

Constants

BINDS  : string = 'binds'
The `binds` key used in initialization and runtime parameter arrays.
THROWABLE  : string = 'throwable'
The `throwable` key used in initialization arrays.

Properties

$alters  : array<string|int, mixed>
The alteration definitions applied to document properties.
$binds  : array<string|int, mixed>|null
The default bind values of the model.
$deferAssignment  : bool|null
Whether schema hydration should run the constructor *before* assigning fetched columns.
$pdo  : PDO|null
The PDO connection used to prepare and execute statements, or `null` when none is configured.
$schema  : null|string|Closure|SchemaResolver
The schema used to hydrate the resources.
$throwable  : bool
Whether the host methods should throw exceptions instead of failing silently.

Methods

alter()  : mixed
Applies defined alterations to a document (array or object) based on a set of rules.
bindValues()  : void
Binds named parameters onto an already-prepared PDO statement.
fetch()  : mixed
Executes a SELECT query and returns its first row.
fetchAll()  : array<string|int, mixed>
Executes a query and returns all of its rows at once.
fetchAllAsGenerator()  : Generator<string|int, object>
Executes a SELECT query and streams its rows one by one through a generator.
fetchColumn()  : mixed
Executes a query and returns the value of a single column from its first row.
fetchColumnArray()  : array<int, string>
Executes a query and returns the first column of every row as a flat list.
getSchema()  : string|null
Resolves the schema to its final string value.
hasSchema()  : bool
Indicates whether a schema is configured.
initializeAlters()  : static
Initializes the `$alters` property from an initialization array.
initializeBinds()  : static
Initializes the `$binds` property from an initialization array.
initializeDefaultFetchMode()  : void
Configures the fetch mode of a statement just before rows are read.
initializeDeferAssignment()  : static
Initializes the `$deferAssignment` property from an options array.
initializePDO()  : static
Initializes the `$pdo` connection from an options array or the DI container.
initializeSchema()  : static
Initializes the `$schema` property from an initialization array.
initializeThrowable()  : static
Initializes the `$throwable` flag from an initialization array.
isConnected()  : bool
Indicates whether a live PDO connection is currently available.
prepareBindVars()  : array<string|int, mixed>
Prepares the binding parameters to inject into a PDO statement.

Constants

BINDS

The `binds` key used in initialization and runtime parameter arrays.

public string BINDS = 'binds'

THROWABLE

The `throwable` key used in initialization arrays.

public string THROWABLE = 'throwable'

Properties

$alters

The alteration definitions applied to document properties.

public array<string|int, mixed> $alters = []

Each key is a property name and each value is either a single Alter constant or an array describing a parameterized/chained alteration.

$binds

The default bind values of the model.

public array<string|int, mixed>|null $binds = []

These values are always merged first by prepareBindVars() and may be overridden by runtime parameters. May be null to indicate "no default binds".

$deferAssignment

Whether schema hydration should run the constructor *before* assigning fetched columns.

public bool|null $deferAssignment = false

Only meaningful when a $schema class is defined: when true, the fetch mode is combined with PDO::FETCH_PROPS_LATE so the object's constructor runs first and the row values then overwrite the defaults it set.

$pdo

The PDO connection used to prepare and execute statements, or `null` when none is configured.

public PDO|null $pdo = null

$schema

The schema used to hydrate the resources.

public null|string|Closure|SchemaResolver $schema = null

A fixed type string, a Closure taking the target and returning a string, or a SchemaResolver. null means no schema is configured.

$throwable

Whether the host methods should throw exceptions instead of failing silently.

public bool $throwable = false

Methods

alter()

Applies defined alterations to a document (array or object) based on a set of rules.

public alter(mixed $document[, array<string|int, mixed>|null $alters = null ]) : mixed

This method inspects the input document and applies transformations according to the provided $alters definitions:

  • If the document is a sequential array (list), the alteration is recursively applied to each element.
  • If the document is an associative array or an object, only the keys defined in $alters are processed.
  • If a key in $alters is associated with a chained alteration (array of alters), each alteration is applied sequentially, passing the output of one as input to the next.
  • Scalar values (string, int, float, bool, resource, null) are returned unchanged unless specifically targeted in $alters.

The $alters parameter allows temporarily overriding or extending the internal $this->alters property for the current method call. Passing null will use the trait's internal $this->alters array.

Parameters
$document : mixed

The input to transform. Can be an associative array, object, or a list of items.

$alters : array<string|int, mixed>|null = null

Optional temporary alter definitions for this call. Keys are property names, values are Alter:: constants or arrays of chained alters.

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

example
class Example
{
    use AlterDocumentTrait;

    public function __construct()
    {
        $this->alters = [
            'price' => Alter::FLOAT,
            'tags'  => [ Alter::ARRAY, Alter::CLEAN ],
            'name'  => [ Alter::TRIM, Alter::UPPERCASE ], // Chained alterations
        ];
    }
}

$input = [
    'price' => '19.99',
    'tags'  => 'foo,bar',
    'name'  => '  john  '
];

$processor = new Example();
$output = $processor->alter($input);

// $output:
// [
//     'price' => 19.99,
//     'tags'  => ['foo', 'bar'],
//     'name'  => 'JOHN',
// ]
Return values
mixed

The transformed document, preserving the input structure (array, object, or list of arrays/objects).

bindValues()

Binds named parameters onto an already-prepared PDO statement.

public bindValues(PDOStatement $statement[, array<string|int, mixed> $bindVars = [] ]) : void

Each key of $bindVars is bound to the matching :key placeholder (the leading colon is prepended automatically). A scalar value is bound with PDO's default type inference; an array value is treated as a [value, type] pair, letting you force a PDO type such as PDO::PARAM_INT or PDO::PARAM_BOOL. An empty $bindVars is a no-op.

Parameters
$statement : PDOStatement

The prepared statement to bind the values onto.

$bindVars : array<string|int, mixed> = []

Associative array of bindings, keyed by placeholder name. Supports:

  • ['id' => 5] — bound with default type inference.
  • ['id' => [5, PDO::PARAM_INT]] — bound with an explicit PDO type.
Tags
example
$statement = $pdo->prepare( 'SELECT * FROM users WHERE id = :id AND active = :active' );
$this->bindValues( $statement , [ 'id' => [ 42 , PDO::PARAM_INT ] , 'active' => true ] );
$statement->execute();

fetch()

Executes a SELECT query and returns its first row.

public fetch(string $query[, array<string|int, mixed> $bindVars = [] ][, bool $throwable = false ]) : mixed

The row is mapped according to the configured fetch mode: a schema instance when a $schema class is set, otherwise a stdClass object built from the associative row. The result is then passed through AlterDocumentTrait::alter() before being returned.

When the statement cannot be prepared, fails to execute or returns no row, null is returned. On error the exception is caught and logged (or printed in CLI), unless $throwable is true in which case it is rethrown. The statement cursor is always closed in the finally block.

Parameters
$query : string

The SQL SELECT query to execute, using :name placeholders.

$bindVars : array<string|int, mixed> = []

Optional named-parameter bindings for the query. Supports:

  • ['id' => 5]
  • ['id' => [5, PDO::PARAM_INT]]
$throwable : bool = false

When true, query failures are rethrown instead of being logged and swallowed (default false).

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

example
$user = $model->fetch( 'SELECT * FROM users WHERE id = :id' , [ 'id' => 123 ] );

if ( $user !== null )
{
    echo $user->email;
}
Return values
mixed

The altered result object/schema instance, or null if no row is found or the query fails.

fetchAll()

Executes a query and returns all of its rows at once.

public fetchAll(string $query[, array<string|int, mixed> $bindVars = [] ][, bool $throwable = false ]) : array<string|int, mixed>

Depending on the configured fetch mode, rows are returned as schema instances (when a $schema class is set) or as associative arrays. The non-empty result set is passed as a whole through AlterDocumentTrait::alter() so registered alterations apply to every element.

An empty array is returned when the statement cannot be prepared, fails to execute or yields no rows. Errors are caught and logged unless $throwable is true. The cursor is always closed.

Parameters
$query : string

The SQL query to execute, using :name placeholders.

$bindVars : array<string|int, mixed> = []

Optional named-parameter bindings for the query. Supports:

  • ['id' => 5]
  • ['id' => [5, PDO::PARAM_INT]]
$throwable : bool = false

When true, query failures are rethrown instead of being logged and swallowed (default false).

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

example
$admins = $model->fetchAll(
    'SELECT * FROM users WHERE role = :role' ,
    [ 'role' => 'admin' ]
);

foreach ( $admins as $admin )
{
    // ...
}
Return values
array<string|int, mixed>

The altered list of results, or an empty array if the query yields nothing or fails while $throwable is false.

fetchAllAsGenerator()

Executes a SELECT query and streams its rows one by one through a generator.

public fetchAllAsGenerator(string $query[, array<string|int, mixed> $bindVars = [] ][, bool $throwable = false ]) : Generator<string|int, object>

This is the memory-efficient counterpart of PDOTrait::fetchAll(): rows are never accumulated in an array. Each row is cast to an object (or hydrated into a schema instance via the configured fetch mode), passed through AlterDocumentTrait::alter() and yielded immediately. The cursor is closed once iteration completes or the generator is discarded.

If the statement cannot be prepared or fails to execute, the generator simply yields nothing. Errors raised during iteration are logged unless $throwable is true.

Parameters
$query : string

The SQL query to execute, using :name placeholders.

$bindVars : array<string|int, mixed> = []

Optional named-parameter bindings for the query (see PDOTrait::bindValues()).

$throwable : bool = false

When true, query failures are rethrown instead of being logged and swallowed (default false).

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

DependencyException

If the dependency cannot be resolved by the container.

NotFoundException

If no entry is found for the given identifier in the container.

ReflectionException

If a class or property cannot be reflected (e.g. during hydration).

example
// Iterate over a million rows without exhausting memory
foreach ( $model->fetchAllAsGenerator( 'SELECT * FROM events' ) as $event )
{
    $this->process( $event );
}
Return values
Generator<string|int, object>

A generator yielding the altered rows one at a time.

fetchColumn()

Executes a query and returns the value of a single column from its first row.

public fetchColumn(string $query[, array<string|int, mixed> $bindVars = [] ][, int $column = 0 ][, bool $throwable = false ]) : mixed

Unlike the other fetch* helpers this one does not apply schema mapping nor alterations — it returns the raw scalar produced by PDOStatement::fetchColumn(). Handy for COUNT(*), MAX(...), an existence check or fetching one field.

Returns null when the statement cannot be prepared, fails to execute or has no row. Errors are logged and swallowed unless $throwable is true. The cursor is always closed.

Parameters
$query : string

The SQL query to execute, using :name placeholders.

$bindVars : array<string|int, mixed> = []

Optional named-parameter bindings for the query (see PDOTrait::bindValues()).

$column : int = 0

Zero-based index of the column to return from the first row (default 0).

$throwable : bool = false

When true, query failures are rethrown instead of being logged and swallowed (default false).

Tags
throws
Exception

If the SQL statement fails to prepare or execute and $throwable is true.

example
$total = (int) $model->fetchColumn(
    'SELECT COUNT(*) FROM users WHERE active = :active' ,
    [ 'active' => true ]
);
Return values
mixed

The column value, or null if no row is found or the query fails.

fetchColumnArray()

Executes a query and returns the first column of every row as a flat list.

public fetchColumnArray(string $query[, array<string|int, mixed> $bindVars = [] ][, bool $throwable = false ]) : array<int, string>

Uses PDO::FETCH_COLUMN, so a single-column SELECT yields a simple list of scalar values. Like PDOTrait::fetchColumn() it applies neither schema mapping nor alterations.

Returns an empty array when the statement cannot be prepared, fails to execute or has no rows. Errors are logged and swallowed unless $throwable is true. The cursor is always closed.

Parameters
$query : string

The SQL query to execute, using :name placeholders.

$bindVars : array<string|int, mixed> = []

Optional named-parameter bindings for the query (see PDOTrait::bindValues()).

$throwable : bool = false

When true, query failures are rethrown instead of being logged and swallowed (default false).

Tags
throws
Exception

If the SQL statement fails to prepare or execute and $throwable is true.

example
$emails = $model->fetchColumnArray( 'SELECT email FROM users WHERE active = 1' );
// [ 'a@example.com' , 'b@example.com' , ... ]
Return values
array<int, string>

The list of first-column values, or an empty array on failure.

getSchema()

Resolves the schema to its final string value.

public getSchema([mixed $target = null ]) : string|null

If $schema is a SchemaResolver or any callable, it is invoked with $target and its return value is used. If it is a plain string it is returned as-is. Returns null when no schema is configured.

Parameters
$target : mixed = null

Optional target passed to the resolver/closure to compute the schema dynamically.

Tags
example
$model->schema = fn( $doc ) => $doc['type'] === 'book' ? 'Book' : 'Thing';
echo $model->getSchema( [ 'type' => 'book' ] ); // "Book"
Return values
string|null

The resolved schema string, or null when none is configured.

hasSchema()

Indicates whether a schema is configured.

public hasSchema() : bool
Return values
bool

true if $schema is not null (string, closure or resolver), false otherwise.

initializeAlters()

Initializes the `$alters` property from an initialization array.

public initializeAlters([array<string|int, mixed> $init = [] ]) : static

The definitions are read from the ModelParam::ALTERS key when present; otherwise the current value is kept. The alter key configuration is then initialized through initializeAlterKey().

Parameters
$init : array<string|int, mixed> = []

Initialization options, typically the model constructor payload.

Return values
static

The current instance, for fluent chaining.

initializeBinds()

Initializes the `$binds` property from an initialization array.

public initializeBinds([array<string|int, mixed> $init = [] ]) : static

The value is read from the self::BINDS key when present; otherwise the current value of $binds is kept.

Parameters
$init : array<string|int, mixed> = []

Initialization options, typically the model constructor payload.

Return values
static

The current instance, for fluent chaining.

initializeDefaultFetchMode()

Configures the fetch mode of a statement just before rows are read.

public initializeDefaultFetchMode(PDOStatement $statement) : void

When $schema names an existing class, rows are hydrated into instances of it via PDO::FETCH_CLASS, combined with PDO::FETCH_PROPS_LATE when $deferAssignment is true (so the constructor runs before columns are assigned). Otherwise the statement falls back to PDO::FETCH_ASSOC. Called internally by every fetch* helper.

Parameters
$statement : PDOStatement

The prepared, executed statement to configure.

initializeDeferAssignment()

Initializes the `$deferAssignment` property from an options array.

public initializeDeferAssignment([array<string|int, mixed> $init = [] ]) : static

Reads the ModelParam::DEFER_ASSIGNMENT key when present, falling back to false.

Parameters
$init : array<string|int, mixed> = []

Initialization options; the deferAssignment boolean key sets the property.

Return values
static

The current instance, i.e. $this, for fluent chaining.

initializePDO()

Initializes the `$pdo` connection from an options array or the DI container.

public initializePDO([array<string|int, mixed> $init = [] ][, Container|null $container = null ]) : static

The ModelParam::PDO key may hold a PDO instance directly, or a string service id. When it is a string and the given container declares that id, the service is resolved from it. Any value that is not ultimately a PDO instance leaves $pdo set to null.

Parameters
$init : array<string|int, mixed> = []

Configuration array; the pdo key holds a PDO instance or a container id.

$container : Container|null = null

Optional DI container used to resolve a string PDO service id.

Tags
throws
ContainerExceptionInterface

If an error occurs while retrieving an entry from the dependency-injection container.

NotFoundExceptionInterface

If no entry is found for the requested identifier in the container.

Return values
static

The current instance, i.e. $this, for fluent chaining.

initializeSchema()

Initializes the `$schema` property from an initialization array.

public initializeSchema([array<string|int, mixed> $init = [] ]) : static

The value is read from the ModelParam::SCHEMA key. It must be null, a string, a Closure or a SchemaResolver; any other type is rejected.

Parameters
$init : array<string|int, mixed> = []

Initialization options (key: ModelParam::SCHEMA).

Tags
throws
InvalidArgumentException

If the value is neither a string, a Closure, nor a SchemaResolver.

Return values
static

The current instance, for fluent chaining.

initializeThrowable()

Initializes the `$throwable` flag from an initialization array.

public initializeThrowable([array<string, mixed> $init = [] ]) : static

Read from the self::THROWABLE key when present; otherwise the current value is kept.

Parameters
$init : array<string, mixed> = []

Initialization options (key: throwable).

Return values
static

The current instance, for fluent chaining.

isConnected()

Indicates whether a live PDO connection is currently available.

public isConnected() : bool

Returns false when no PDO instance is configured. Otherwise it queries PDO::ATTR_CONNECTION_STATUS; a non-null status means the connection is up. Any PDOException raised while reading the attribute is treated as "not connected".

Return values
bool

true if a PDO instance is set and reports a connection status, false otherwise.

prepareBindVars()

Prepares the binding parameters to inject into a PDO statement.

public prepareBindVars([array<string|int, mixed> $init = [] ]) : array<string|int, mixed>

The default $binds of the model are merged first, then overridden by the runtime values found under the self::BINDS key of $init. Keys present in both win on the runtime side.

Parameters
$init : array<string|int, mixed> = []

Runtime parameters; the values under the binds key are merged on top of the defaults.

Tags
example
class MyModel
{
    use BindsTrait;
}

$model = new MyModel();
$model->binds = [ 'id' => 42 ];

$params = $model->prepareBindVars([ 'binds' => [ 'status' => 'active' ] ]);
// $params === [ 'id' => 42 , 'status' => 'active' ]
Return values
array<string|int, mixed>

The merged associative array of bind variables ready to bind on a prepared statement.

On this page

Search results