Skip to main content

Connection configuration

A ConnectionConfig describes exactly one named connection. It is a readonly value object with named constructor arguments and no setters, so a connection cannot change shape after it is described.

use Dirthara\Database\Connection\Driver\DriverName;
use Dirthara\Database\Connection\ValueObjects\ConnectionConfig;

$config = new ConnectionConfig(
driver: DriverName::PostgresSql,
name: 'reporting',
host: 'postgres',
port: 5432,
database: 'analytics',
username: 'reporter',
password: $password,
charset: 'UTF8',
options: [PDO::ATTR_TIMEOUT => 5],
);

Options

OptionTypeDefaultMeaning
driverDriverNamerequiredWhich database this connection speaks to. Selects the registered driver that opens it.
namestring'default'The key the ConnectionManager resolves this connection by. Must be unique across the configs you register.
host?stringnullServer hostname or IP. Required by MySQL, PostgreSQL, and SQL Server; ignored by SQLite.
port?intnullServer port. Falls back to the driver's default when null. Ignored by SQLite.
database?stringnullDatabase name. Optional for MySQL, PostgreSQL, and SQL Server, which then connect without selecting one. Required by SQLite, where it is a file path or :memory:.
username?stringnullLogin user. Marked #[SensitiveParameter], so it is hidden in stack traces. Not used by SQLite.
password?stringnullLogin password. Marked #[SensitiveParameter], so it is hidden in stack traces. Not used by SQLite.
charset?stringnullClient character set. Applied differently per driver, and rejected by two of them — see driver-specific options.
optionsarray<int, mixed>[]PDO attributes keyed by the PDO::ATTR_* constants. Overrides the defaults the drivers set.
dsnarray<string, scalar>[]Driver-specific parameters appended to the DSN, such as sslmode or TrustServerCertificate. Rejected by SQLite, which has nowhere to put them.

Every argument except driver has a default, and they are all named, so a config only mentions what it actually needs.

The charset option

charset accepts an identifier only: letters, digits, hyphens, and underscores, matching /^[A-Za-z0-9_-]+$/. Anything else throws a ConnectionException before it can reach a DSN or a SET statement. That is deliberate — the value ends up in SQL that cannot be parameterised.

The options array

options are the fourth argument to PDO's constructor: attributes keyed by integer constants, not a bag of package settings.

Two defaults are set for every driver:

AttributeValueWhy
PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTIONFailures throw instead of returning false, which is what the exception mapping relies on.
PDO::ATTR_DEFAULT_FETCH_MODEPDO::FETCH_ASSOCRows are string-keyed maps, matching the Result return types.

MySQL adds one more:

AttributeValueWhy
PDO::ATTR_EMULATE_PREPARESfalseReal server-side prepared statements, so bound parameter types are honoured.

Anything you pass in options wins over all of these.

caution

Overriding PDO::ATTR_ERRMODE or PDO::ATTR_DEFAULT_FETCH_MODE breaks the guarantees the rest of the package documents. With a silent error mode, driver failures stop being exceptions; with another fetch mode, Result no longer returns string-keyed rows.

Driver-specific DSN parameters

options are PDO attributes; dsn is everything the database's own connection string accepts and the config has no field for. Each pair is appended as ;Name=Value.

new ConnectionConfig(
driver: DriverName::PostgresSql,
host: 'postgres',
database: 'app',
dsn: ['sslmode' => 'require'],
);

new ConnectionConfig(
driver: DriverName::SqlServer,
host: 'sqlserver',
dsn: ['Encrypt' => 'yes', 'TrustServerCertificate' => 'no'],
);

This is how you require TLS. PostgreSQL takes sslmode; SQL Server takes Encrypt and TrustServerCertificate, and ODBC Driver 18 already encrypts by default, so what you usually need is a certificate it can verify. MySQL takes unix_socket among others.

Both halves of a pair are validated when the connection opens, because a DSN is assembled by concatenation and neither half can be a bound parameter:

  • The name must be an identifier: a letter, then letters, digits, or underscores. 'Trust Server Certificate' is refused.
  • The value must not contain a semicolon, so it cannot append a field of its own. 'no;Database=other' is refused.

Either violation throws a ConnectionException carrying the connection's diagnostics. SQLite has no Key=Value DSN, so it refuses any parameter rather than accepting and ignoring it.

caution

Do not put credentials here. username and password have their own fields, which keep them out of diagnostics and stack traces; anything in dsn is shown in full when the config is dumped.

Diagnostics and debugging

diagnostics() returns the subset of the config that is safe to log — connection, driver, host, port, and database, with null values dropped. This is what gets merged into exception context.

$config->diagnostics();
// ['connection' => 'reporting', 'driver' => 'pgsql', 'host' => 'postgres', 'port' => 5432, 'database' => 'analytics']

Dumping the object with var_dump() shows every option, but the password is replaced with [redacted] — present or absent is visible, the value is not. The username is shown in full, because debugging a permission failure usually needs it and the driver's own error message contains it anyway.

Both are marked #[SensitiveParameter], which keeps them out of stack traces, and neither is part of diagnostics(), so neither reaches exception context or a log line. dsn is left out of diagnostics() for the same reason: a driver-specific parameter can carry more than it looks like.