From 0ccf1c9d19a0d489eca0636cb674cba54a1829f4 Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 10 Nov 2025 12:50:39 +1100 Subject: [PATCH 1/5] Addresses Issue #81 --- composer.json | 1 + composer.lock | 137 +++++++++++++++++- src/ResultSet/AbstractResultSet.php | 84 ++++------- src/ResultSet/HydratingResultSet.php | 38 ++--- src/ResultSet/ResultSet.php | 44 ++---- src/ResultSet/ResultSetInterface.php | 17 +-- .../ResultSet/ResultSetIntegrationTest.php | 2 +- 7 files changed, 193 insertions(+), 130 deletions(-) diff --git a/composer.json b/composer.json index eac7d3eb1..29a6263dd 100644 --- a/composer.json +++ b/composer.json @@ -36,6 +36,7 @@ "require-dev": { "laminas/laminas-coding-standard": "^3.0.1", "laminas/laminas-eventmanager": "^3.14.0", + "laminas/laminas-hydrator": "^4.6.0", "phpstan/phpstan": "^2.1", "phpstan/phpstan-phpunit": "^2.0", "phpunit/phpunit": "^11.5.15", diff --git a/composer.lock b/composer.lock index e64a135fb..7dadb0811 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "886d3b3b68ad9ef73938895688890230", + "content-hash": "8b6c816b6f330e6685aca2f074f44eea", "packages": [ { "name": "brick/varexporter", @@ -532,6 +532,83 @@ ], "time": "2025-10-31T10:29:01+00:00" }, + { + "name": "laminas/laminas-hydrator", + "version": "4.17.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-hydrator.git", + "reference": "626c5e446fdfa27865dfe3cd29123108408c2555" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-hydrator/zipball/626c5e446fdfa27865dfe3cd29123108408c2555", + "reference": "626c5e446fdfa27865dfe3cd29123108408c2555", + "shasum": "" + }, + "require": { + "laminas/laminas-stdlib": "^3.20", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "webmozart/assert": "^1.11" + }, + "conflict": { + "laminas/laminas-servicemanager": "<3.14.0", + "zendframework/zend-hydrator": "*" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~3.0", + "laminas/laminas-eventmanager": "^3.13.1", + "laminas/laminas-modulemanager": "^2.16.0", + "laminas/laminas-serializer": "^2.17.0", + "laminas/laminas-servicemanager": "^3.24.0", + "phpbench/phpbench": "^1.3.1", + "phpunit/phpunit": "^11.5.42", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^6.13.1" + }, + "suggest": { + "laminas/laminas-eventmanager": "^3.13, to support aggregate hydrator usage", + "laminas/laminas-serializer": "^2.17, to use the SerializableStrategy", + "laminas/laminas-servicemanager": "^3.22, to support hydrator plugin manager usage" + }, + "type": "library", + "extra": { + "laminas": { + "component": "Laminas\\Hydrator", + "config-provider": "Laminas\\Hydrator\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Laminas\\Hydrator\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Serialize objects to arrays, and vice versa", + "homepage": "https://laminas.dev", + "keywords": [ + "hydrator", + "laminas" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-hydrator/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-hydrator/issues", + "rss": "https://github.com/laminas/laminas-hydrator/releases.atom", + "source": "https://github.com/laminas/laminas-hydrator" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2025-11-06T11:05:29+00:00" + }, { "name": "myclabs/deep-copy", "version": "1.13.4", @@ -2653,6 +2730,64 @@ } ], "time": "2024-10-16T06:55:17+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.12.1", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", + "php": "^7.2 || ^8.0" + }, + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.12.1" + }, + "time": "2025-10-29T15:56:20+00:00" } ], "aliases": [], diff --git a/src/ResultSet/AbstractResultSet.php b/src/ResultSet/AbstractResultSet.php index 5f5938434..1becd0cab 100644 --- a/src/ResultSet/AbstractResultSet.php +++ b/src/ResultSet/AbstractResultSet.php @@ -4,10 +4,12 @@ use ArrayIterator; use Countable; +use Exception; use Iterator; use IteratorAggregate; use PhpDb\Adapter\Driver\ResultInterface; -// phpcs:ignore SlevomatCodingStandard.Namespaces.UnusedUses.UnusedUse +use PhpDb\ResultSet\Exception\InvalidArgumentException; +use PhpDb\ResultSet\Exception\RuntimeException; use ReturnTypeWillChange; use function count; @@ -19,7 +21,7 @@ use function method_exists; use function reset; -abstract class AbstractResultSet implements Iterator, ResultSetInterface +abstract class AbstractResultSet implements ResultSetInterface { /** * if -1, datasource is already buffered @@ -27,31 +29,24 @@ abstract class AbstractResultSet implements Iterator, ResultSetInterface * if false, explicitly disabled * if null, default state - nothing, but can buffer until iteration started * if array, already buffering - * - * @var mixed */ - protected $buffer; + protected mixed $buffer; - /** @var null|int */ - protected $count; + protected ?int $count = null; - /** @var Iterator|IteratorAggregate|ResultInterface */ - protected $dataSource; + protected Iterator|IteratorAggregate|ResultInterface|null $dataSource = null; - /** @var int */ - protected $fieldCount; + protected ?int $fieldCount = null; - /** @var int */ - protected $position = 0; + protected int $position = 0; /** * Set the data source for the result set * - * @param array|Iterator|IteratorAggregate|ResultInterface $dataSource + * @throws InvalidArgumentException|Exception * @return $this Provides a fluent interface - * @throws Exception\InvalidArgumentException */ - public function initialize($dataSource) + public function initialize(iterable $dataSource): ResultSetInterface { // reset buffering if (is_array($this->buffer)) { @@ -82,7 +77,7 @@ public function initialize($dataSource) } elseif ($dataSource instanceof Iterator) { $this->dataSource = $dataSource; } else { - throw new Exception\InvalidArgumentException( + throw new InvalidArgumentException( 'DataSource provided is not an array, nor does it implement Iterator or IteratorAggregate' ); } @@ -92,12 +87,12 @@ public function initialize($dataSource) /** * @return $this Provides a fluent interface - * @throws Exception\RuntimeException + * @throws RuntimeException */ - public function buffer() + public function buffer(): ResultSetInterface { if ($this->buffer === -2) { - throw new Exception\RuntimeException('Buffering must be enabled before iteration is started'); + throw new RuntimeException('Buffering must be enabled before iteration is started'); } elseif ($this->buffer === null) { $this->buffer = []; if ($this->dataSource instanceof ResultInterface) { @@ -107,8 +102,7 @@ public function buffer() return $this; } - /** @return bool */ - public function isBuffered() + public function isBuffered(): bool { if ($this->buffer === -1 || is_array($this->buffer)) { return true; @@ -118,20 +112,16 @@ public function isBuffered() /** * Get the data source used to create the result set - * - * @return null|Iterator */ - public function getDataSource() + public function getDataSource(): ResultInterface|IteratorAggregate|Iterator|null { return $this->dataSource; } /** * Retrieve count of fields in individual rows of the result set - * - * @return int */ - public function getFieldCount() + public function getFieldCount(): mixed { if (null !== $this->fieldCount) { return $this->fieldCount; @@ -149,7 +139,7 @@ public function getFieldCount() } $row = $dataSource->current(); - if (is_object($row) && $row instanceof Countable) { + if ($row instanceof Countable) { $this->fieldCount = $row->count(); return $this->fieldCount; } @@ -161,11 +151,8 @@ public function getFieldCount() /** * Iterator: move pointer to next item - * - * @return void */ - #[ReturnTypeWillChange] - public function next() + public function next(): void { if ($this->buffer === null) { $this->buffer = -2; // implicitly disable buffering from here on @@ -179,22 +166,16 @@ public function next() /** * Iterator: retrieve current key - * - * @return mixed */ - #[ReturnTypeWillChange] - public function key() + public function key(): int { return $this->position; } /** * Iterator: get current item - * - * @return array|null */ - #[ReturnTypeWillChange] - public function current() + public function current(): array|object|null { if (-1 === $this->buffer) { // datasource was an array when the resultset was initialized @@ -215,11 +196,8 @@ public function current() /** * Iterator: is pointer valid? - * - * @return bool */ - #[ReturnTypeWillChange] - public function valid() + public function valid(): bool { if (is_array($this->buffer) && isset($this->buffer[$this->position])) { return true; @@ -234,11 +212,8 @@ public function valid() /** * Iterator: rewind - * - * @return void */ - #[ReturnTypeWillChange] - public function rewind() + public function rewind(): void { if (! is_array($this->buffer)) { if ($this->dataSource instanceof Iterator) { @@ -252,11 +227,9 @@ public function rewind() /** * Countable: return count of rows - * - * @return int */ #[ReturnTypeWillChange] - public function count() + public function count(): ?int { if ($this->count !== null) { return $this->count; @@ -272,10 +245,9 @@ public function count() /** * Cast result set to array of arrays * - * @return array - * @throws Exception\RuntimeException If any row is not castable to an array. + * @throws RuntimeException If any row is not castable to an array. */ - public function toArray() + public function toArray(): array { $return = []; foreach ($this as $row) { @@ -291,7 +263,7 @@ public function toArray() && ! method_exists($row, 'getArrayCopy') ) ) { - throw new Exception\RuntimeException( + throw new RuntimeException( 'Rows as part of this DataSource, with type ' . gettype($row) . ' cannot be cast to an array' ); } diff --git a/src/ResultSet/HydratingResultSet.php b/src/ResultSet/HydratingResultSet.php index 2343b8282..c89e81d96 100644 --- a/src/ResultSet/HydratingResultSet.php +++ b/src/ResultSet/HydratingResultSet.php @@ -3,33 +3,25 @@ namespace PhpDb\ResultSet; use ArrayObject; -use Laminas\Hydrator\ArraySerializable; use Laminas\Hydrator\ArraySerializableHydrator; use Laminas\Hydrator\HydratorInterface; -use function class_exists; use function gettype; use function is_array; use function is_object; class HydratingResultSet extends AbstractResultSet { - /** @var HydratorInterface */ - protected $hydrator; + protected HydratorInterface $hydrator; - /** @var null|object */ - protected $objectPrototype; + protected ?object $objectPrototype; /** * Constructor - * - * @param null|object $objectPrototype */ - public function __construct(?HydratorInterface $hydrator = null, $objectPrototype = null) + public function __construct(?HydratorInterface $hydrator = null, ?object $objectPrototype = null) { - $defaultHydratorClass = class_exists(ArraySerializableHydrator::class) - ? ArraySerializableHydrator::class - : ArraySerializable::class; + $defaultHydratorClass = ArraySerializableHydrator::class; $this->setHydrator($hydrator ?: new $defaultHydratorClass()); $this->setObjectPrototype($objectPrototype ?: new ArrayObject()); } @@ -37,11 +29,10 @@ public function __construct(?HydratorInterface $hydrator = null, $objectPrototyp /** * Set the row object prototype * - * @param object $objectPrototype - * @return $this Provides a fluent interface * @throws Exception\InvalidArgumentException + * @return $this Provides a fluent interface */ - public function setObjectPrototype($objectPrototype) + public function setObjectPrototype(object $objectPrototype): static { if (! is_object($objectPrototype)) { throw new Exception\InvalidArgumentException( @@ -54,10 +45,8 @@ public function setObjectPrototype($objectPrototype) /** * Get the row object prototype - * - * @return object */ - public function getObjectPrototype() + public function getObjectPrototype(): ?object { return $this->objectPrototype; } @@ -67,7 +56,7 @@ public function getObjectPrototype() * * @return $this Provides a fluent interface */ - public function setHydrator(HydratorInterface $hydrator) + public function setHydrator(HydratorInterface $hydrator): static { $this->hydrator = $hydrator; return $this; @@ -75,20 +64,16 @@ public function setHydrator(HydratorInterface $hydrator) /** * Get the hydrator to use for each row object - * - * @return HydratorInterface */ - public function getHydrator() + public function getHydrator(): HydratorInterface { return $this->hydrator; } /** * Iterator: get current item - * - * @return object|null */ - public function current() + public function current(): ?object { if ($this->buffer === null) { $this->buffer = -2; // implicitly disable buffering from here on @@ -108,10 +93,9 @@ public function current() /** * Cast result set to array of arrays * - * @return array * @throws Exception\RuntimeException If any row is not castable to an array. */ - public function toArray() + public function toArray(): array { $return = []; foreach ($this as $row) { diff --git a/src/ResultSet/ResultSet.php b/src/ResultSet/ResultSet.php index 4b33bf493..ce1bca0f6 100644 --- a/src/ResultSet/ResultSet.php +++ b/src/ResultSet/ResultSet.php @@ -6,7 +6,6 @@ use function in_array; use function is_array; -use function is_object; use function method_exists; class ResultSet extends AbstractResultSet @@ -16,31 +15,25 @@ class ResultSet extends AbstractResultSet /** * Allowed return types - * - * @var array */ - protected $allowedReturnTypes = [ + protected array $allowedReturnTypes = [ self::TYPE_ARRAYOBJECT, self::TYPE_ARRAY, ]; - /** @var ArrayObject */ - protected $arrayObjectPrototype; + protected ArrayObject $arrayObjectPrototype; /** * Return type to use when returning an object from the set * * @var ResultSet::TYPE_ARRAYOBJECT|ResultSet::TYPE_ARRAY */ - protected $returnType = self::TYPE_ARRAYOBJECT; + protected mixed $returnType = self::TYPE_ARRAYOBJECT; /** * Constructor - * - * @param string $returnType - * @param null|ArrayObject $arrayObjectPrototype */ - public function __construct($returnType = self::TYPE_ARRAYOBJECT, $arrayObjectPrototype = null) + public function __construct(string $returnType = self::TYPE_ARRAYOBJECT, ?ArrayObject $arrayObjectPrototype = null) { if (in_array($returnType, $this->allowedReturnTypes, true)) { $this->returnType = $returnType; @@ -55,21 +48,14 @@ public function __construct($returnType = self::TYPE_ARRAYOBJECT, $arrayObjectPr /** * Set the row object prototype * - * @param ArrayObject $arrayObjectPrototype - * @return $this Provides a fluent interface * @throws Exception\InvalidArgumentException + * @return $this Provides a fluent interface */ - public function setArrayObjectPrototype($arrayObjectPrototype) + public function setArrayObjectPrototype(ArrayObject $arrayObjectPrototype): static { - if ( - ! is_object($arrayObjectPrototype) - || ( - ! $arrayObjectPrototype instanceof ArrayObject - && ! method_exists($arrayObjectPrototype, 'exchangeArray') - ) - ) { + if (! method_exists($arrayObjectPrototype, 'exchangeArray')) { throw new Exception\InvalidArgumentException( - 'Object must be of type ArrayObject, or at least implement exchangeArray' + 'Object must at least implement exchangeArray' ); } $this->arrayObjectPrototype = $arrayObjectPrototype; @@ -78,33 +64,25 @@ public function setArrayObjectPrototype($arrayObjectPrototype) /** * Get the row object prototype - * - * @return ArrayObject */ - public function getArrayObjectPrototype() + public function getArrayObjectPrototype(): ArrayObject { return $this->arrayObjectPrototype; } /** * Get the return type to use when returning objects from the set - * - * @return string */ - public function getReturnType() + public function getReturnType(): string { return $this->returnType; } - /** - * @return array|ArrayObject|null - */ - public function current() + public function current(): array|object|null { $data = parent::current(); if ($this->returnType === self::TYPE_ARRAYOBJECT && is_array($data)) { - /** @var ArrayObject $ao */ $ao = clone $this->arrayObjectPrototype; if ($ao instanceof ArrayObject || method_exists($ao, 'exchangeArray')) { $ao->exchangeArray($data); diff --git a/src/ResultSet/ResultSetInterface.php b/src/ResultSet/ResultSetInterface.php index a0b693691..f41ebfa65 100644 --- a/src/ResultSet/ResultSetInterface.php +++ b/src/ResultSet/ResultSetInterface.php @@ -3,26 +3,19 @@ namespace PhpDb\ResultSet; use Countable; -use Traversable; +use Iterator; -interface ResultSetInterface extends Traversable, Countable +interface ResultSetInterface extends Iterator, Countable { /** - * Can be anything traversable|array - * - * @abstract - * @param iterable $dataSource - * @return mixed + * Can be anything iterable|array */ - public function initialize($dataSource); + public function initialize(iterable $dataSource): ResultSetInterface; /** * Field terminology is more correct as information coming back * from the database might be a column, and/or the result of an * operation or intersection of some data - * - * @abstract - * @return mixed */ - public function getFieldCount(); + public function getFieldCount(): mixed; } diff --git a/test/unit/ResultSet/ResultSetIntegrationTest.php b/test/unit/ResultSet/ResultSetIntegrationTest.php index 7fbaa7ef7..f1f90c6e9 100644 --- a/test/unit/ResultSet/ResultSetIntegrationTest.php +++ b/test/unit/ResultSet/ResultSetIntegrationTest.php @@ -4,12 +4,12 @@ use ArrayIterator; use ArrayObject; +use Override; use PhpDb\Adapter\Driver\ResultInterface; use PhpDb\ResultSet\AbstractResultSet; use PhpDb\ResultSet\Exception\InvalidArgumentException; use PhpDb\ResultSet\Exception\RuntimeException; use PhpDb\ResultSet\ResultSet; -use Override; use PHPUnit\Framework\Attributes\CoversMethod; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\Exception; From 3b79b9b9c67e639e12bfe969ef0f55488d0b0aba Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 10 Nov 2025 12:53:31 +1100 Subject: [PATCH 2/5] Fixes StatementContainer typing issue with interface --- src/Adapter/StatementContainer.php | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/src/Adapter/StatementContainer.php b/src/Adapter/StatementContainer.php index 4bf07f134..17364a596 100644 --- a/src/Adapter/StatementContainer.php +++ b/src/Adapter/StatementContainer.php @@ -4,16 +4,11 @@ class StatementContainer implements StatementContainerInterface { - /** @var string */ - protected $sql = ''; + protected string $sql = ''; - /** @var ParameterContainer */ - protected $parameterContainer; + protected ParameterContainer $parameterContainer; - /** - * @param string|null $sql - */ - public function __construct($sql = null, ?ParameterContainer $parameterContainer = null) + public function __construct(?string $sql = null, ?ParameterContainer $parameterContainer = null) { if ($sql) { $this->setSql($sql); @@ -25,16 +20,13 @@ public function __construct($sql = null, ?ParameterContainer $parameterContainer * @param string $sql * @return $this Provides a fluent interface */ - public function setSql($sql) + public function setSql($sql): StatementContainerInterface { $this->sql = $sql; return $this; } - /** - * @return string - */ - public function getSql() + public function getSql(): ?string { return $this->sql; } @@ -42,16 +34,13 @@ public function getSql() /** * @return $this Provides a fluent interface */ - public function setParameterContainer(ParameterContainer $parameterContainer) + public function setParameterContainer(ParameterContainer $parameterContainer): StatementContainerInterface { $this->parameterContainer = $parameterContainer; return $this; } - /** - * @return null|ParameterContainer - */ - public function getParameterContainer() + public function getParameterContainer(): ?ParameterContainer { return $this->parameterContainer; } From a0c7785b82f9e6ab332c1ddae3dfd2d55a4982da Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 10 Nov 2025 13:08:20 +1100 Subject: [PATCH 3/5] Fixed issue with no default value for $buffer --- src/ResultSet/AbstractResultSet.php | 2 +- test/unit/ResultSet/AbstractResultSetTest.php | 7 +++---- test/unit/ResultSet/ResultSetIntegrationTest.php | 6 ++++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ResultSet/AbstractResultSet.php b/src/ResultSet/AbstractResultSet.php index 1becd0cab..208d654a9 100644 --- a/src/ResultSet/AbstractResultSet.php +++ b/src/ResultSet/AbstractResultSet.php @@ -30,7 +30,7 @@ abstract class AbstractResultSet implements ResultSetInterface * if null, default state - nothing, but can buffer until iteration started * if array, already buffering */ - protected mixed $buffer; + protected mixed $buffer = null; protected ?int $count = null; diff --git a/test/unit/ResultSet/AbstractResultSetTest.php b/test/unit/ResultSet/AbstractResultSetTest.php index ae502f121..9fb0c6b27 100644 --- a/test/unit/ResultSet/AbstractResultSetTest.php +++ b/test/unit/ResultSet/AbstractResultSetTest.php @@ -15,6 +15,8 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use TypeError; + use function assert; #[CoversMethod(AbstractResultSet::class, 'initialize')] @@ -54,10 +56,7 @@ public function testInitialize(): void ['id' => 3, 'name' => 'three'], ])); - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage( - 'DataSource provided is not an array, nor does it implement Iterator or IteratorAggregate' - ); + $this->expectException(TypeError::class); $resultSet->initialize('foo'); } diff --git a/test/unit/ResultSet/ResultSetIntegrationTest.php b/test/unit/ResultSet/ResultSetIntegrationTest.php index f1f90c6e9..956b6f4f6 100644 --- a/test/unit/ResultSet/ResultSetIntegrationTest.php +++ b/test/unit/ResultSet/ResultSetIntegrationTest.php @@ -18,6 +18,8 @@ use SplStack; use stdClass; +use TypeError; + use function is_array; use function random_int; use function var_export; @@ -79,7 +81,7 @@ public static function invalidReturnTypes(): array #[DataProvider('invalidReturnTypes')] public function testSettingInvalidReturnTypeRaisesException(mixed $type): void { - $this->expectException(InvalidArgumentException::class); + $this->expectException(TypeError::class); new ResultSet(ResultSet::TYPE_ARRAYOBJECT, $type); } @@ -133,7 +135,7 @@ public function testInvalidDataSourceRaisesException(mixed $dataSource) // this is valid return; } - $this->expectException(InvalidArgumentException::class); + $this->expectException(TypeError::class); $this->resultSet->initialize($dataSource); } From 0c5e9b33b2cd5eaae33513fc8a37c3a3439b051e Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 10 Nov 2025 13:14:15 +1100 Subject: [PATCH 4/5] Fixed issue with no default value for $buffer --- src/ResultSet/AbstractResultSet.php | 2 +- test/unit/ResultSet/AbstractResultSetTest.php | 6 ++---- test/unit/ResultSet/ResultSetIntegrationTest.php | 2 -- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/ResultSet/AbstractResultSet.php b/src/ResultSet/AbstractResultSet.php index 208d654a9..7f71be995 100644 --- a/src/ResultSet/AbstractResultSet.php +++ b/src/ResultSet/AbstractResultSet.php @@ -30,7 +30,7 @@ abstract class AbstractResultSet implements ResultSetInterface * if null, default state - nothing, but can buffer until iteration started * if array, already buffering */ - protected mixed $buffer = null; + protected int|array|bool|null $buffer = null; protected ?int $count = null; diff --git a/test/unit/ResultSet/AbstractResultSetTest.php b/test/unit/ResultSet/AbstractResultSetTest.php index 9fb0c6b27..1a2be1af4 100644 --- a/test/unit/ResultSet/AbstractResultSetTest.php +++ b/test/unit/ResultSet/AbstractResultSetTest.php @@ -3,18 +3,16 @@ namespace PhpDbTest\ResultSet; use ArrayIterator; +use Override; +use PDOStatement; use PhpDb\Adapter\Driver\Pdo\Result; use PhpDb\Adapter\Driver\ResultInterface; use PhpDb\ResultSet\AbstractResultSet; -use PhpDb\ResultSet\Exception\InvalidArgumentException; use PhpDb\ResultSet\Exception\RuntimeException; -use Override; -use PDOStatement; use PHPUnit\Framework\Attributes\CoversMethod; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; - use TypeError; use function assert; diff --git a/test/unit/ResultSet/ResultSetIntegrationTest.php b/test/unit/ResultSet/ResultSetIntegrationTest.php index 956b6f4f6..2b92a4e08 100644 --- a/test/unit/ResultSet/ResultSetIntegrationTest.php +++ b/test/unit/ResultSet/ResultSetIntegrationTest.php @@ -7,7 +7,6 @@ use Override; use PhpDb\Adapter\Driver\ResultInterface; use PhpDb\ResultSet\AbstractResultSet; -use PhpDb\ResultSet\Exception\InvalidArgumentException; use PhpDb\ResultSet\Exception\RuntimeException; use PhpDb\ResultSet\ResultSet; use PHPUnit\Framework\Attributes\CoversMethod; @@ -17,7 +16,6 @@ use Random\RandomException; use SplStack; use stdClass; - use TypeError; use function is_array; From 72f3b71bdc436d2bd62a0e7fb4751debaf5d889a Mon Sep 17 00:00:00 2001 From: Simon Mundy Date: Mon, 10 Nov 2025 14:56:58 +1100 Subject: [PATCH 5/5] Corrected typing for $returnType --- src/ResultSet/ResultSet.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/ResultSet/ResultSet.php b/src/ResultSet/ResultSet.php index ce1bca0f6..ef1b7a5ac 100644 --- a/src/ResultSet/ResultSet.php +++ b/src/ResultSet/ResultSet.php @@ -25,21 +25,17 @@ class ResultSet extends AbstractResultSet /** * Return type to use when returning an object from the set - * - * @var ResultSet::TYPE_ARRAYOBJECT|ResultSet::TYPE_ARRAY */ - protected mixed $returnType = self::TYPE_ARRAYOBJECT; + protected string $returnType = self::TYPE_ARRAYOBJECT; /** * Constructor */ public function __construct(string $returnType = self::TYPE_ARRAYOBJECT, ?ArrayObject $arrayObjectPrototype = null) { - if (in_array($returnType, $this->allowedReturnTypes, true)) { - $this->returnType = $returnType; - } else { - $this->returnType = self::TYPE_ARRAYOBJECT; - } + $this->returnType = in_array($returnType, $this->allowedReturnTypes, true) ? + $returnType : self::TYPE_ARRAYOBJECT; + if ($this->returnType === self::TYPE_ARRAYOBJECT) { $this->setArrayObjectPrototype($arrayObjectPrototype ?: new ArrayObject([], ArrayObject::ARRAY_AS_PROPS)); }