diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 9a50e9b..a6dc006 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -15,6 +15,9 @@ jobs: operating-system: - ubuntu-latest php-version: + - '8.1' + - '8.2' + - '8.3' - '8.4' steps: - name: Checkout diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c2f6dd..e40898c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 6.1.0 + +- Reintroduce PHP 8.1–8.3 support; `ExtendedPdo::connect()` is not supported in those versions, and requires PHP 8.4, by @francislavoie in https://github.com/auraphp/Aura.Sql/pull/245 +- Mark all `$dsn` and `$password` parameters as `#[\SensitiveParameter]` to prevent leaking sensitive information in error messages, by @francislavoie in https://github.com/auraphp/Aura.Sql/pull/245 + ## 6.0.0 - CHG: BC Break `ExtendedPdo::connect` renamed to `ExtendedPdo::lazyConnect` diff --git a/composer.json b/composer.json index e4412c1..66f142d 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ } ], "require": { - "php": "^8.4", + "php": ">=8.1", "psr/log": "^1.0 || ^2.0 || ^3.0", "ext-pdo": "*" }, diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 2e61e13..6f31223 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,6 +1,7 @@ - + + ./src diff --git a/src/DecoratedPdo.php b/src/DecoratedPdo.php index 901669e..523abd5 100644 --- a/src/DecoratedPdo.php +++ b/src/DecoratedPdo.php @@ -45,9 +45,9 @@ public function __construct(PDO $pdo, ?ProfilerInterface $profiler = null) } public static function connect( - string $dsn, + #[\SensitiveParameter] string $dsn, ?string $username = null, - ?string $password = null, + #[\SensitiveParameter] ?string $password = null, ?array $options = [] ): static { return new static(\PDO::connect($dsn, $username, $password, $options)); diff --git a/src/ExtendedPdo.php b/src/ExtendedPdo.php index 019c2e2..8387573 100644 --- a/src/ExtendedPdo.php +++ b/src/ExtendedPdo.php @@ -8,160 +8,8 @@ */ namespace Aura\Sql; -use Aura\Sql\Profiler\Profiler; -use Aura\Sql\Profiler\ProfilerInterface; -use PDO; - -/** - * - * A lazy-connecting PDO with extended methods. - * - * @package Aura.Sql - * - */ -class ExtendedPdo extends AbstractExtendedPdo -{ - /** - * - * Constructor arguments for instantiating the PDO connection. - * - * @var array - * - */ - protected array $args = []; - - /** - * - * Constructor. - * - * This overrides the parent so that it can take connection attributes as a - * constructor parameter, and set them after connection. - * - * @param string $dsn The data source name for the connection. - * - * @param string|null $username The username for the connection. - * - * @param string|null $password The password for the connection. - * - * @param array $options Driver-specific options for the connection. - * - * @param array $queries Queries to execute after the connection. - * - * @param \Aura\Sql\Profiler\ProfilerInterface|null $profiler Tracks and logs query profiles. - * - * @see http://php.net/manual/en/pdo.construct.php - */ - public function __construct( - string $dsn, - ?string $username = null, - ?string $password = null, - array $options = [], - array $queries = [], - ?ProfilerInterface $profiler = null - ) { - // if no error mode is specified, use exceptions - if (! isset($options[PDO::ATTR_ERRMODE])) { - $options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION; - } - - // retain the arguments for later - $this->args = [ - $dsn, - $username, - $password, - $options, - $queries - ]; - - // retain a profiler, instantiating a default one if needed - $this->setProfiler($profiler ?? new Profiler()); - - // retain a query parser - $parts = explode(":", $dsn); - $parser = $this->newParser($parts[0]); - $this->setParser($parser); - - // set quotes for identifier names - $this->setQuoteName($parts[0]); - } - - public static function connect( - string $dsn, - ?string $username = null, - ?string $password = null, - ?array $options = [] - ): static { - return new static($dsn, $username, $password, $options); - } - - /** - * - * Connects to the database. - * - * @return void - */ - public function lazyConnect(): void - { - if ($this->pdo) { - return; - } - - // connect - $this->profiler->start(__FUNCTION__); - list($dsn, $username, $password, $options, $queries) = $this->args; - $this->pdo = new PDO($dsn, $username, $password, $options); - $this->profiler->finish(); - - // connection-time queries - foreach ($queries as $query) { - $this->exec($query); - } - } - - /** - * - * Disconnects from the database. - * - * @return void - * - */ - public function disconnect(): void - { - $this->profiler->start(__FUNCTION__); - $this->pdo = null; - $this->profiler->finish(); - } - - /** - * - * The purpose of this method is to hide sensitive data from stack traces. - * - * @return array - * - */ - public function __debugInfo(): array - { - return [ - 'args' => [ - $this->args[0], - '****', - '****', - $this->args[3], - $this->args[4], - ], - ]; - } - - /** - * - * Return the inner PDO (if any) - * - * @return \PDO - * - */ - public function getPdo(): PDO - { - $this->lazyConnect(); - return $this->pdo; - } -} +if (PHP_VERSION_ID < 80400) { + require_once __DIR__ . '/ExtendedPdoPHP83.php'; +} else { + require_once __DIR__ . '/ExtendedPdoPHP84.php'; +} \ No newline at end of file diff --git a/src/ExtendedPdoPHP83.php b/src/ExtendedPdoPHP83.php new file mode 100644 index 0000000..1e86966 --- /dev/null +++ b/src/ExtendedPdoPHP83.php @@ -0,0 +1,163 @@ +args = [ + $dsn, + $username, + $password, + $options, + $queries + ]; + + // retain a profiler, instantiating a default one if needed + $this->setProfiler($profiler ?? new Profiler()); + + // retain a query parser + $parts = explode(":", $dsn); + $parser = $this->newParser($parts[0]); + $this->setParser($parser); + + // set quotes for identifier names + $this->setQuoteName($parts[0]); + } + + public function connect(): void + { + throw new \RuntimeException('The connect() method is no longer supported in Aura.Sql v6. Use lazyConnect() instead.'); + } + + /** + * + * Connects to the database. + * + * @return void + */ + public function lazyConnect(): void + { + if ($this->pdo) { + return; + } + + // connect + $this->profiler->start(__FUNCTION__); + list($dsn, $username, $password, $options, $queries) = $this->args; + $this->pdo = new PDO($dsn, $username, $password, $options); + $this->profiler->finish(); + + // connection-time queries + foreach ($queries as $query) { + $this->exec($query); + } + } + + /** + * + * Disconnects from the database. + * + * @return void + * + */ + public function disconnect(): void + { + $this->profiler->start(__FUNCTION__); + $this->pdo = null; + $this->profiler->finish(); + } + + /** + * + * The purpose of this method is to hide sensitive data from stack traces. + * + * @return array + * + */ + public function __debugInfo(): array + { + return [ + 'args' => [ + $this->args[0], + '****', + '****', + $this->args[3], + $this->args[4], + ], + ]; + } + + /** + * + * Return the inner PDO (if any) + * + * @return \PDO + * + */ + public function getPdo(): PDO + { + $this->lazyConnect(); + return $this->pdo; + } +} diff --git a/src/ExtendedPdoPHP84.php b/src/ExtendedPdoPHP84.php new file mode 100644 index 0000000..106caec --- /dev/null +++ b/src/ExtendedPdoPHP84.php @@ -0,0 +1,167 @@ +args = [ + $dsn, + $username, + $password, + $options, + $queries + ]; + + // retain a profiler, instantiating a default one if needed + $this->setProfiler($profiler ?? new Profiler()); + + // retain a query parser + $parts = explode(":", $dsn); + $parser = $this->newParser($parts[0]); + $this->setParser($parser); + + // set quotes for identifier names + $this->setQuoteName($parts[0]); + } + + public static function connect( + #[\SensitiveParameter] string $dsn, + ?string $username = null, + #[\SensitiveParameter] ?string $password = null, + ?array $options = null + ): static { + return new static($dsn, $username, $password, $options ?? []); + } + + /** + * + * Connects to the database. + * + * @return void + */ + public function lazyConnect(): void + { + if ($this->pdo) { + return; + } + + // connect + $this->profiler->start(__FUNCTION__); + list($dsn, $username, $password, $options, $queries) = $this->args; + $this->pdo = new PDO($dsn, $username, $password, $options); + $this->profiler->finish(); + + // connection-time queries + foreach ($queries as $query) { + $this->exec($query); + } + } + + /** + * + * Disconnects from the database. + * + * @return void + * + */ + public function disconnect(): void + { + $this->profiler->start(__FUNCTION__); + $this->pdo = null; + $this->profiler->finish(); + } + + /** + * + * The purpose of this method is to hide sensitive data from stack traces. + * + * @return array + * + */ + public function __debugInfo(): array + { + return [ + 'args' => [ + $this->args[0], + '****', + '****', + $this->args[3], + $this->args[4], + ], + ]; + } + + /** + * + * Return the inner PDO (if any) + * + * @return \PDO + * + */ + public function getPdo(): PDO + { + $this->lazyConnect(); + return $this->pdo; + } +} diff --git a/src/PdoInterface.php b/src/PdoInterface.php index 7f29545..cb8e9cf 100644 --- a/src/PdoInterface.php +++ b/src/PdoInterface.php @@ -8,206 +8,8 @@ */ namespace Aura\Sql; -use PDO; -use PDOStatement; - -/** - * - * An interface to the native PDO object. - * - * @package Aura.Sql - * - */ -interface PdoInterface -{ - /** - * - * Begins a transaction and turns off autocommit mode. - * - * @return bool True on success, false on failure. - * - * @see http://php.net/manual/en/pdo.begintransaction.php - * - */ - public function beginTransaction(): bool; - - /** - * - * Commits the existing transaction and restores autocommit mode. - * - * @return bool True on success, false on failure. - * - * @see http://php.net/manual/en/pdo.commit.php - * - */ - public function commit(): bool; - - /** - * - * Introduced in 6.x due to PHP 8.4 change. This is a BC break for Aura.Sql. - * - * @param string $dsn The Data Source Name, or DSN, contains the information required to connect to the database. - * - * @param string | null $username The user name for the DSN string. This parameter is optional for some PDO drivers. - * - * @param string | null $password The password for the DSN string. This parameter is optional for some PDO drivers. - * - * @param array | null $options A key=>value array of driver-specific connection options. - * - * @return \PDO Returns an instance of a generic PDO instance. - * - * @see https://www.php.net/manual/en/pdo.connect.php - */ - public static function connect( - string $dsn, - ?string $username = null, - #[\SensitiveParameter] ?string $password = null, - ?array $options = null - ): static; - - /** - * - * Gets the most recent error code. - * - * @return string|null - */ - public function errorCode(): ?string; - - /** - * - * Gets the most recent error info. - * - * @return array - * - */ - public function errorInfo(): array; - - /** - * - * Executes an SQL statement and returns the number of affected rows. - * - * @param string $statement The SQL statement to execute. - * - * @return int|false The number of rows affected. - * - * @see http://php.net/manual/en/pdo.exec.php - * - */ - public function exec(string $statement): int|false; - - /** - * - * Gets a PDO attribute value. - * - * @param int $attribute The PDO::ATTR_* constant. - * - * @return bool|int|string|array|null The value for the attribute. - * - */ - public function getAttribute(int $attribute): bool|int|string|array|null; - - /** - * - * Returns all currently available PDO drivers. - * - * @return array - * - */ - public static function getAvailableDrivers(): array; - - /** - * - * Is a transaction currently active? - * - * @return bool - * - * @see http://php.net/manual/en/pdo.intransaction.php - * - */ - public function inTransaction(): bool; - - /** - * - * Returns the last inserted autoincrement sequence value. - * - * @param string|null $name The name of the sequence to check; typically needed - * only for PostgreSQL, where it takes the form of `__seq`. - * - * @return string|false - * - * @see http://php.net/manual/en/pdo.lastinsertid.php - * - */ - public function lastInsertId(?string $name = null): string|false; - - /** - * - * Prepares an SQL statement for execution. - * - * @param string $query The SQL statement to prepare for execution. - * - * @param array $options Set these attributes on the returned - * PDOStatement. - * - * @return \PDOStatement|false - * - * @see http://php.net/manual/en/pdo.prepare.php - */ - public function prepare(string $query, array $options = []): PDOStatement|false; - - /** - * - * Queries the database and returns a PDOStatement. - * - * @param string $query The SQL statement to prepare and execute. - * - * @param int|null $fetchMode - * - * @param mixed ...$fetch_mode_args Optional fetch-related parameters. - * - * @return \PDOStatement|false - * - * @see http://php.net/manual/en/pdo.query.php - * - */ - public function query(string $query, ?int $fetchMode = null, ...$fetch_mode_args): PDOStatement|false; - - /** - * - * Quotes a value for use in an SQL statement. - * - * @param string|int|array|float|null $value The value to quote. - * - * @param int $type A data type hint for the database driver. - * - * @return string|false The quoted value. - * - * @see http://php.net/manual/en/pdo.quote.php - * - */ - public function quote(string|int|array|float|null $value, int $type = PDO::PARAM_STR): string|false; - - /** - * - * Rolls back the current transaction and restores autocommit mode. - * - * @return bool True on success, false on failure. - * - * @see http://php.net/manual/en/pdo.rollback.php - * - */ - public function rollBack(): bool; - - /** - * - * Sets a PDO attribute value. - * - * @param int $attribute The PDO::ATTR_* constant. - * - * @param mixed $value The value for the attribute. - * - * @return bool - * - */ - public function setAttribute(int $attribute, mixed $value): bool; -} +if (PHP_VERSION_ID < 80400) { + require_once __DIR__ . '/PdoInterfacePHP83.php'; +} else { + require_once __DIR__ . '/PdoInterfacePHP84.php'; +} \ No newline at end of file diff --git a/src/PdoInterfacePHP83.php b/src/PdoInterfacePHP83.php new file mode 100644 index 0000000..156b246 --- /dev/null +++ b/src/PdoInterfacePHP83.php @@ -0,0 +1,190 @@ +__seq`. + * + * @return string|false + * + * @see http://php.net/manual/en/pdo.lastinsertid.php + * + */ + public function lastInsertId(?string $name = null): string|false; + + /** + * + * Prepares an SQL statement for execution. + * + * @param string $query The SQL statement to prepare for execution. + * + * @param array $options Set these attributes on the returned + * PDOStatement. + * + * @return \PDOStatement|false + * + * @see http://php.net/manual/en/pdo.prepare.php + */ + public function prepare(string $query, array $options = []): PDOStatement|false; + + /** + * + * Queries the database and returns a PDOStatement. + * + * @param string $query The SQL statement to prepare and execute. + * + * @param int|null $fetchMode + * + * @param mixed ...$fetch_mode_args Optional fetch-related parameters. + * + * @return \PDOStatement|false + * + * @see http://php.net/manual/en/pdo.query.php + * + */ + public function query(string $query, ?int $fetchMode = null, ...$fetch_mode_args): PDOStatement|false; + + /** + * + * Quotes a value for use in an SQL statement. + * + * @param string|int|array|float|null $value The value to quote. + * + * @param int $type A data type hint for the database driver. + * + * @return string|false The quoted value. + * + * @see http://php.net/manual/en/pdo.quote.php + * + */ + public function quote(string|int|array|float|null $value, int $type = PDO::PARAM_STR): string|false; + + /** + * + * Rolls back the current transaction and restores autocommit mode. + * + * @return bool True on success, false on failure. + * + * @see http://php.net/manual/en/pdo.rollback.php + * + */ + public function rollBack(): bool; + + /** + * + * Sets a PDO attribute value. + * + * @param int $attribute The PDO::ATTR_* constant. + * + * @param mixed $value The value for the attribute. + * + * @return bool + * + */ + public function setAttribute(int $attribute, mixed $value): bool; +} diff --git a/src/PdoInterfacePHP84.php b/src/PdoInterfacePHP84.php new file mode 100644 index 0000000..54ee273 --- /dev/null +++ b/src/PdoInterfacePHP84.php @@ -0,0 +1,214 @@ +value array of driver-specific connection options. + * + * @return \PDO Returns an instance of a generic PDO instance. + * + * @see https://www.php.net/manual/en/pdo.connect.php + */ + public static function connect( + #[\SensitiveParameter] string $dsn, + ?string $username = null, + #[\SensitiveParameter] ?string $password = null, + ?array $options = null + ): static; + + /** + * + * Gets the most recent error code. + * + * @return string|null + */ + public function errorCode(): ?string; + + /** + * + * Gets the most recent error info. + * + * @return array + * + */ + public function errorInfo(): array; + + /** + * + * Executes an SQL statement and returns the number of affected rows. + * + * @param string $statement The SQL statement to execute. + * + * @return int|false The number of rows affected. + * + * @see http://php.net/manual/en/pdo.exec.php + * + */ + public function exec(string $statement): int|false; + + /** + * + * Gets a PDO attribute value. + * + * @param int $attribute The PDO::ATTR_* constant. + * + * @return bool|int|string|array|null The value for the attribute. + * + */ + public function getAttribute(int $attribute): bool|int|string|array|null; + + /** + * + * Returns all currently available PDO drivers. + * + * @return array + * + */ + public static function getAvailableDrivers(): array; + + /** + * + * Is a transaction currently active? + * + * @return bool + * + * @see http://php.net/manual/en/pdo.intransaction.php + * + */ + public function inTransaction(): bool; + + /** + * + * Returns the last inserted autoincrement sequence value. + * + * @param string|null $name The name of the sequence to check; typically needed + * only for PostgreSQL, where it takes the form of `
__seq`. + * + * @return string|false + * + * @see http://php.net/manual/en/pdo.lastinsertid.php + * + */ + public function lastInsertId(?string $name = null): string|false; + + /** + * + * Prepares an SQL statement for execution. + * + * @param string $query The SQL statement to prepare for execution. + * + * @param array $options Set these attributes on the returned + * PDOStatement. + * + * @return \PDOStatement|false + * + * @see http://php.net/manual/en/pdo.prepare.php + */ + public function prepare(string $query, array $options = []): PDOStatement|false; + + /** + * + * Queries the database and returns a PDOStatement. + * + * @param string $query The SQL statement to prepare and execute. + * + * @param int|null $fetchMode + * + * @param mixed ...$fetch_mode_args Optional fetch-related parameters. + * + * @return \PDOStatement|false + * + * @see http://php.net/manual/en/pdo.query.php + * + */ + public function query(string $query, ?int $fetchMode = null, ...$fetch_mode_args): PDOStatement|false; + + /** + * + * Quotes a value for use in an SQL statement. + * + * @param string|int|array|float|null $value The value to quote. + * + * @param int $type A data type hint for the database driver. + * + * @return string|false The quoted value. + * + * @see http://php.net/manual/en/pdo.quote.php + * + */ + public function quote(string|int|array|float|null $value, int $type = PDO::PARAM_STR): string|false; + + /** + * + * Rolls back the current transaction and restores autocommit mode. + * + * @return bool True on success, false on failure. + * + * @see http://php.net/manual/en/pdo.rollback.php + * + */ + public function rollBack(): bool; + + /** + * + * Sets a PDO attribute value. + * + * @param int $attribute The PDO::ATTR_* constant. + * + * @param mixed $value The value for the attribute. + * + * @return bool + * + */ + public function setAttribute(int $attribute, mixed $value): bool; +} diff --git a/tests/DecoratedPdoTest.php b/tests/DecoratedPdoTest.php index 7f1dbff..68bd666 100644 --- a/tests/DecoratedPdoTest.php +++ b/tests/DecoratedPdoTest.php @@ -15,7 +15,7 @@ protected function newPdo() public function testDisconnect() { $this->assertTrue($this->pdo->isConnected()); - $this->expectException(Exception\CannotDisconnect::CLASS); + $this->expectException(Exception\CannotDisconnect::class); $this->pdo->disconnect(); } diff --git a/tests/ExtendedConnectPdoTest.php b/tests/ExtendedConnectPdoTest.php index 25d5269..65b72e9 100644 --- a/tests/ExtendedConnectPdoTest.php +++ b/tests/ExtendedConnectPdoTest.php @@ -4,8 +4,17 @@ class ExtendedConnectPdoTest extends \Aura\Sql\ExtendedPdoTest { + public function setUp(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('PHP 8.3 and earlier do not support the new connect method.'); + } + parent::setUp(); + } + protected function newPdo() { + // PHP 8.4+ has a new connect method to get a driver-specific subclass return ExtendedPdo::connect('sqlite::memory:'); } } \ No newline at end of file diff --git a/tests/Parser/AbstractParserTest.php b/tests/Parser/AbstractParserTest.php index d3787ac..c83f4fd 100644 --- a/tests/Parser/AbstractParserTest.php +++ b/tests/Parser/AbstractParserTest.php @@ -58,14 +58,14 @@ public function testDoubleQuotedIdentifier() { $parameters = ['foo' => ['bar', 'baz']]; $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); } @@ -74,23 +74,23 @@ public function testStringConstants() { $parameters = ['foo' => ['bar', 'baz']]; $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); } @@ -99,43 +99,43 @@ public function testEscapedCharactersInStringConstants() { $parameters = ['foo' => ['bar', 'baz']]; $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); $sql = <<< 'SQL' -SELECT "Escaping \" :foo \"" -SQL; + SELECT "Escaping \" :foo \"" + SQL; list ($statement, $values) = $this->rebuild($sql, $parameters); $this->assertEquals($sql, $statement); -// $sql = << 'bar', 'foo_0' => 'baz']; -// list ($statement, $values) = $this->rebuild($sql, $parameters); -// $this->assertEquals($expectedStatement, $statement); -// $this->assertEquals($expectedValues, $values); + // $sql = << 'bar', 'foo_0' => 'baz']; + // list ($statement, $values) = $this->rebuild($sql, $parameters); + // $this->assertEquals($expectedStatement, $statement); + // $this->assertEquals($expectedValues, $values); $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); } diff --git a/tests/Parser/MysqlParserTest.php b/tests/Parser/MysqlParserTest.php index 0a85baf..a64b054 100644 --- a/tests/Parser/MysqlParserTest.php +++ b/tests/Parser/MysqlParserTest.php @@ -12,15 +12,15 @@ public function testBacktickString() { $parameters = ['foo' => ['bar', 'baz']]; $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); } diff --git a/tests/Parser/PgsqlParserTest.php b/tests/Parser/PgsqlParserTest.php index b3cd440..190d76c 100644 --- a/tests/Parser/PgsqlParserTest.php +++ b/tests/Parser/PgsqlParserTest.php @@ -12,9 +12,9 @@ public function testUnicodeDoubleQuotedIdentifier() { $parameters = ['a000' => ['foo', 'bar']]; $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); } @@ -23,15 +23,15 @@ public function testCStyleStringConstants() { $parameters = ['foo' => ['bar', 'baz']]; $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); } @@ -64,8 +64,8 @@ public function testTypeCasting() { $parameters = ['TEXT' => ['bar', 'baz']]; $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); } @@ -74,11 +74,11 @@ public function testArrayAccessor() { $parameters = ['2' => ['bar', 'baz']]; $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); } @@ -87,8 +87,8 @@ public function testInvalidPlaceholderName() { $parameters = [']' => ['bar', 'baz']]; $sql = <<rebuild($sql, $parameters); $this->assertEquals($sql, $statement); }