From d372b48175ddb2f2cd925bf5bcba9c82ac0f1a10 Mon Sep 17 00:00:00 2001 From: Krzysztof Ciszewski Date: Sat, 29 Nov 2025 14:20:40 +0100 Subject: [PATCH 1/6] added types --- .../PersistentCollectionInterface.php | 70 +++------ .../PersistentCollectionTrait.php | 144 +++++++++++------- tests/Tests/PersistentCollectionTest.php | 4 +- 3 files changed, 111 insertions(+), 107 deletions(-) diff --git a/src/PersistentCollection/PersistentCollectionInterface.php b/src/PersistentCollection/PersistentCollectionInterface.php index c71b5d17b7..0b87ba1a64 100644 --- a/src/PersistentCollection/PersistentCollectionInterface.php +++ b/src/PersistentCollection/PersistentCollectionInterface.php @@ -26,50 +26,42 @@ interface PersistentCollectionInterface extends Collection { /** * Sets the document manager and unit of work (used during merge operations). - * - * @return void */ - public function setDocumentManager(DocumentManager $dm); + public function setDocumentManager(DocumentManager $dm): void; /** * Sets the array of raw mongo data that will be used to initialize this collection. * * @param mixed[] $mongoData - * - * @return void */ - public function setMongoData(array $mongoData); + public function setMongoData(array $mongoData): void; /** * Gets the array of raw mongo data that will be used to initialize this collection. * * @return mixed[] $mongoData */ - public function getMongoData(); + public function getMongoData(): array; /** * Set hints to account for during reconstitution/lookup of the documents. * * @param Hints $hints - * - * @return void */ - public function setHints(array $hints); + public function setHints(array $hints): void; /** * Get hints to account for during reconstitution/lookup of the documents. * * @return Hints $hints */ - public function getHints(); + public function getHints(): array; /** * Initializes the collection by loading its contents from the database * if the collection is not yet initialized. - * - * @return void */ - public function initialize(); + public function initialize(): void; /** * Gets a boolean flag indicating whether this collection is dirty which means @@ -77,111 +69,93 @@ public function initialize(); * * @return bool TRUE if the collection is dirty, FALSE otherwise. */ - public function isDirty(); + public function isDirty(): bool; /** * Sets a boolean flag, indicating whether this collection is dirty. * * @param bool $dirty Whether the collection should be marked dirty or not. - * - * @return void */ - public function setDirty($dirty); + public function setDirty(bool $dirty): void; /** * Sets the collection's owning document together with the AssociationMapping that * describes the association between the owner and the elements of the collection. * * @phpstan-param FieldMapping $mapping - * - * @return void */ - public function setOwner(object $document, array $mapping); + public function setOwner(object $document, array $mapping): void; /** * Tells this collection to take a snapshot of its current state reindexing * itself numerically if using save strategy that is enforcing BSON array. * Reindexing is safe as snapshot is taken only after synchronizing collection * with database or clearing it. - * - * @return void */ - public function takeSnapshot(); + public function takeSnapshot(): void; /** * Clears the internal snapshot information and sets isDirty to true if the collection * has elements. - * - * @return void */ - public function clearSnapshot(); + public function clearSnapshot(): void; /** * Returns the last snapshot of the elements in the collection. * * @return object[] The last snapshot of the elements. */ - public function getSnapshot(); + public function getSnapshot(): array; /** @return array */ - public function getDeleteDiff(); + public function getDeleteDiff(): array; /** * Get objects that were removed, unlike getDeleteDiff this doesn't care about indices. * * @return list */ - public function getDeletedDocuments(); + public function getDeletedDocuments(): array; /** @return array */ - public function getInsertDiff(); + public function getInsertDiff(): array; /** * Get objects that were added, unlike getInsertDiff this doesn't care about indices. * * @return list */ - public function getInsertedDocuments(); + public function getInsertedDocuments(): array; /** * Gets the collection owner. */ public function getOwner(): ?object; - /** - * @return array - * @phpstan-return FieldMapping - */ - public function getMapping(); + /** @phpstan-return FieldMapping */ + public function getMapping(): array; /** - * @return ClassMetadata * @phpstan-return ClassMetadata * * @throws MongoDBException */ - public function getTypeClass(); + public function getTypeClass(): ClassMetadata; /** * Sets the initialized flag of the collection, forcing it into that state. - * - * @param bool $bool - * - * @return void */ - public function setInitialized($bool); + public function setInitialized(bool $bool): void; /** * Checks whether this collection has been initialized. - * - * @return bool */ - public function isInitialized(); + public function isInitialized(): bool; /** * Returns the wrapped Collection instance. * * @return Collection */ - public function unwrap(); + public function unwrap(): Collection; } diff --git a/src/PersistentCollection/PersistentCollectionTrait.php b/src/PersistentCollection/PersistentCollectionTrait.php index 79dae29566..4585544e1c 100644 --- a/src/PersistentCollection/PersistentCollectionTrait.php +++ b/src/PersistentCollection/PersistentCollectionTrait.php @@ -28,6 +28,8 @@ /** * Trait with methods needed to implement PersistentCollectionInterface. * + * @internal + * * @phpstan-import-type Hints from UnitOfWork * @phpstan-import-type FieldMapping from ClassMetadata * @template TKey of array-key @@ -97,33 +99,35 @@ trait PersistentCollectionTrait */ private array $hints = []; - public function setDocumentManager(DocumentManager $dm) + public function setDocumentManager(DocumentManager $dm): void { $this->dm = $dm; $this->uow = $dm->getUnitOfWork(); } - public function setMongoData(array $mongoData) + public function setMongoData(array $mongoData): void { $this->mongoData = $mongoData; } - public function getMongoData() + /** @return mixed[] */ + public function getMongoData(): array { return $this->mongoData; } - public function setHints(array $hints) + public function setHints(array $hints): void { $this->hints = $hints; } - public function getHints() + /** @return array */ + public function getHints(): array { return $this->hints; } - public function initialize() + public function initialize(): void { if ($this->initialized || ! $this->mapping) { return; @@ -179,7 +183,7 @@ private function changed(): void $this->uow->scheduleForSynchronization($this->owner); } - public function isDirty() + public function isDirty(): bool { if ($this->isDirty) { return true; @@ -198,18 +202,18 @@ public function isDirty() return false; } - public function setDirty($dirty) + public function setDirty(bool $dirty): void { $this->isDirty = $dirty; } - public function setOwner(object $document, array $mapping) + public function setOwner(object $document, array $mapping): void { $this->owner = $document; $this->mapping = $mapping; } - public function takeSnapshot() + public function takeSnapshot(): void { if ($this->mapping !== null && CollectionHelper::isList($this->mapping['strategy'])) { $array = $this->coll->toArray(); @@ -223,18 +227,20 @@ public function takeSnapshot() $this->isDirty = false; } - public function clearSnapshot() + public function clearSnapshot(): void { $this->snapshot = []; $this->isDirty = $this->coll->count() !== 0; } - public function getSnapshot() + /** @return array */ + public function getSnapshot(): array { return $this->snapshot; } - public function getDeleteDiff() + /** @return T[] */ + public function getDeleteDiff(): array { return array_udiff_assoc( $this->snapshot, @@ -243,7 +249,8 @@ public function getDeleteDiff() ); } - public function getDeletedDocuments() + /** @return list */ + public function getDeletedDocuments(): array { $coll = $this->coll->toArray(); $loadedObjectsByOid = array_combine(array_map('spl_object_id', $this->snapshot), $this->snapshot); @@ -252,7 +259,8 @@ public function getDeletedDocuments() return array_values(array_diff_key($loadedObjectsByOid, $newObjectsByOid)); } - public function getInsertDiff() + /** @return T[] */ + public function getInsertDiff(): array { return array_udiff_assoc( $this->coll->toArray(), @@ -261,7 +269,8 @@ public function getInsertDiff() ); } - public function getInsertedDocuments() + /** @return list */ + public function getInsertedDocuments(): array { $coll = $this->coll->toArray(); $newObjectsByOid = array_combine(array_map('spl_object_id', $coll), $coll); @@ -275,12 +284,14 @@ public function getOwner(): ?object return $this->owner; } - public function getMapping() + /** @return array */ + public function getMapping(): array { return $this->mapping; } - public function getTypeClass() + /** @return ClassMetadata */ + public function getTypeClass(): ClassMetadata { if (! isset($this->dm)) { throw new MongoDBException('No DocumentManager is associated with this PersistentCollection, please set one using setDocumentManager method.'); @@ -297,36 +308,43 @@ public function getTypeClass() return $this->dm->getClassMetadata($this->mapping['targetDocument']); } - public function setInitialized($bool) + public function setInitialized(bool $bool): void { $this->initialized = $bool; } - public function isInitialized() + public function isInitialized(): bool { return $this->initialized; } - public function first() + /** @return T|null */ + public function first(): ?object { $this->initialize(); return $this->coll->first(); } - public function last() + /** @return T|null */ + public function last(): ?object { $this->initialize(); return $this->coll->last(); } - public function remove($key) + /** + * @param mixed $key + * + * @return bool|T|null + */ + public function remove(mixed $key): bool|object|null { return $this->doRemove($key, false); } - public function removeElement($element) + public function removeElement($element): bool { $this->initialize(); $removed = $this->coll->removeElement($element); @@ -340,7 +358,8 @@ public function removeElement($element) return $removed; } - public function containsKey($key) + /** @param TKey $key */ + public function containsKey(string|int $key): bool { $this->initialize(); @@ -348,47 +367,50 @@ public function containsKey($key) } /** @template TMaybeContained */ - public function contains($element) + public function contains(mixed $element): bool { $this->initialize(); return $this->coll->contains($element); } - public function exists(Closure $p) + public function exists(Closure $p): bool { $this->initialize(); return $this->coll->exists($p); } - /** - * @phpstan-return (TMaybeContained is T ? TKey|false : false) - * - * @template TMaybeContained - */ - public function indexOf($element) + /** @return TKey|false */ + public function indexOf(mixed $element): string|int|false { $this->initialize(); return $this->coll->indexOf($element); } - public function get($key) + /** + * @param TKey $key + * + * @return T|null + */ + public function get(string|int $key): mixed { $this->initialize(); return $this->coll->get($key); } - public function getKeys() + /** @return list */ + public function getKeys(): array { $this->initialize(); return $this->coll->getKeys(); } - public function getValues() + /** @return list */ + public function getValues(): array { $this->initialize(); @@ -405,17 +427,17 @@ public function count() return $this->coll->count(); } - public function set($key, $value) + public function set($key, $value): void { $this->doSet($key, $value, false); } - public function add($element) + public function add($element): bool { return $this->doAdd($element, false); } - public function isEmpty() + public function isEmpty(): bool { return $this->initialized ? $this->coll->isEmpty() : $this->count() === 0; } @@ -432,42 +454,44 @@ public function getIterator() return $this->coll->getIterator(); } - public function map(Closure $func) + public function map(Closure $func): BaseCollection { $this->initialize(); return $this->coll->map($func); } - public function filter(Closure $p) + public function filter(Closure $p): BaseCollection { $this->initialize(); return $this->coll->filter($p); } - public function forAll(Closure $p) + public function forAll(Closure $p): bool { $this->initialize(); return $this->coll->forAll($p); } - public function partition(Closure $p) + /** @return array{0: BaseCollection, 1: BaseCollection} */ + public function partition(Closure $p): array { $this->initialize(); return $this->coll->partition($p); } - public function toArray() + /** @return array */ + public function toArray(): array { $this->initialize(); return $this->coll->toArray(); } - public function clear() + public function clear(): void { if ($this->initialized && $this->isEmpty()) { return; @@ -498,7 +522,8 @@ public function clear() $this->takeSnapshot(); } - public function slice($offset, $length = null) + /** @return array */ + public function slice(int $offset, int|null $length = null): array { $this->initialize(); @@ -511,7 +536,7 @@ public function slice($offset, $length = null) * * @return string[] */ - public function __sleep() + public function __sleep(): array { return ['coll', 'initialized', 'mongoData', 'snapshot', 'isDirty', 'hints']; } @@ -569,30 +594,35 @@ public function offsetSet($offset, $value) * @return void */ #[ReturnTypeWillChange] - public function offsetUnset($offset) + public function offsetUnset(mixed $offset) { $this->doRemove($offset, true); } - public function key() + /** @return TKey|null */ + public function key(): int|string|null { return $this->coll->key(); } /** * Gets the element of the collection at the current iterator position. + * + * @phpstan-return T|false */ - public function current() + public function current(): object|false { return $this->coll->current(); } - public function next() + /** @phpstan-return T|false */ + public function next(): object|false { return $this->coll->next(); } - public function unwrap() + /** @return BaseCollection */ + public function unwrap(): BaseCollection { return $this->coll; } @@ -608,7 +638,7 @@ public function unwrap() * 4. Lazy loading grabs documents from old owner object. * 5. New collection is connected to old owner and leads to duplicate keys. */ - public function __clone() + public function __clone(): void { if (is_object($this->coll)) { $this->coll = clone $this->coll; @@ -630,7 +660,7 @@ public function __clone() * * @return true */ - private function doAdd($value, $arrayAccess) + private function doAdd($value, bool $arrayAccess): true { /* Initialize the collection before calling add() so this append operation * uses the appropriate key. Otherwise, we risk overwriting original data @@ -662,7 +692,7 @@ private function doAdd($value, $arrayAccess) * : T|true|null * ) */ - private function doRemove($offset, bool $arrayAccess) + private function doRemove(mixed $offset, bool $arrayAccess): bool|object|null { $this->initialize(); if ($arrayAccess) { @@ -732,7 +762,7 @@ private function needsSchedulingForSynchronization(): bool * * @phpstan-return T|null */ - public function findFirst(Closure $p) + public function findFirst(Closure $p): ?object { if (! method_exists($this->coll, 'findFirst')) { throw new BadMethodCallException('findFirst() is only available since doctrine/collections v2'); @@ -750,7 +780,7 @@ public function findFirst(Closure $p) * @phpstan-template TReturn * @phpstan-template TInitial */ - public function reduce(Closure $func, $initial = null) + public function reduce(Closure $func, mixed $initial = null): mixed { if (! method_exists($this->coll, 'reduce')) { throw new BadMethodCallException('reduce() is only available since doctrine/collections v2'); diff --git a/tests/Tests/PersistentCollectionTest.php b/tests/Tests/PersistentCollectionTest.php index 41b52f1dd2..befe2c3d27 100644 --- a/tests/Tests/PersistentCollectionTest.php +++ b/tests/Tests/PersistentCollectionTest.php @@ -29,7 +29,7 @@ public function testSlice(): void $collection->expects($this->once()) ->method('slice') ->with($start, $limit) - ->willReturn(true); + ->willReturn([]); $pCollection = new PersistentCollection($collection, $this->dm, $this->uow); $pCollection->slice($start, $limit); } @@ -294,7 +294,7 @@ public function testOffsetUnsetIsForwarded(): void public function testRemoveIsForwarded(): void { $collection = $this->getMockCollection(); - $collection->expects($this->once())->method('remove')->willReturn(2); + $collection->expects($this->once())->method('remove')->willReturn(null); $pcoll = new PersistentCollection($collection, $this->dm, $this->uow); $pcoll->remove(0); self::assertTrue($pcoll->isDirty()); From d29db3e039348328a998a7d5f65ca7e5eb71388d Mon Sep 17 00:00:00 2001 From: Krzysztof Ciszewski Date: Sat, 29 Nov 2025 17:47:07 +0100 Subject: [PATCH 2/6] phpcs fix --- .../PersistentCollectionTrait.php | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/PersistentCollection/PersistentCollectionTrait.php b/src/PersistentCollection/PersistentCollectionTrait.php index 4585544e1c..ad98e3784f 100644 --- a/src/PersistentCollection/PersistentCollectionTrait.php +++ b/src/PersistentCollection/PersistentCollectionTrait.php @@ -334,11 +334,7 @@ public function last(): ?object return $this->coll->last(); } - /** - * @param mixed $key - * - * @return bool|T|null - */ + /** @return bool|T|null */ public function remove(mixed $key): bool|object|null { return $this->doRemove($key, false); @@ -588,11 +584,7 @@ public function offsetSet($offset, $value) $this->doSet($offset, $value, true); } - /** - * @param mixed $offset - * - * @return void - */ + /** @return void */ #[ReturnTypeWillChange] public function offsetUnset(mixed $offset) { @@ -656,7 +648,6 @@ public function __clone(): void * Actual logic for adding an element to the collection. * * @param mixed $value - * @param bool $arrayAccess * * @return true */ @@ -683,8 +674,6 @@ private function doAdd($value, bool $arrayAccess): true /** * Actual logic for removing element by its key. * - * @param mixed $offset - * * @return bool|T|null * @phpstan-return ( * $arrayAccess is false From 0a4dd6098108181a545109972d6bba2de76331de Mon Sep 17 00:00:00 2001 From: Krzysztof Ciszewski Date: Sun, 30 Nov 2025 15:26:12 +0100 Subject: [PATCH 3/6] add missing types and docblocks --- .../PersistentCollectionTrait.php | 85 ++++++++++--------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/src/PersistentCollection/PersistentCollectionTrait.php b/src/PersistentCollection/PersistentCollectionTrait.php index ad98e3784f..4eefc4297d 100644 --- a/src/PersistentCollection/PersistentCollectionTrait.php +++ b/src/PersistentCollection/PersistentCollectionTrait.php @@ -340,7 +340,8 @@ public function remove(mixed $key): bool|object|null return $this->doRemove($key, false); } - public function removeElement($element): bool + /** @param T $element */ + public function removeElement(mixed $element): bool { $this->initialize(); $removed = $this->coll->removeElement($element); @@ -362,7 +363,11 @@ public function containsKey(string|int $key): bool return $this->coll->containsKey($key); } - /** @template TMaybeContained */ + /** + * @param T $element + * + * @template TMaybeContained + */ public function contains(mixed $element): bool { $this->initialize(); @@ -377,7 +382,12 @@ public function exists(Closure $p): bool return $this->coll->exists($p); } - /** @return TKey|false */ + /** + * @param T $element + * @phpstan-return (TMaybeContained is T ? TKey|false : false) + * + * @phpstan-template TMaybeContained + */ public function indexOf(mixed $element): string|int|false { $this->initialize(); @@ -390,7 +400,7 @@ public function indexOf(mixed $element): string|int|false * * @return T|null */ - public function get(string|int $key): mixed + public function get(string|int $key): ?object { $this->initialize(); @@ -413,9 +423,7 @@ public function getValues(): array return $this->coll->getValues(); } - /** @return int */ - #[ReturnTypeWillChange] - public function count() + public function count(): int { // Workaround around not being able to directly count inverse collections anymore $this->initialize(); @@ -423,12 +431,17 @@ public function count() return $this->coll->count(); } - public function set($key, $value): void + /** + * @param TKey $key + * @param T|null $value + */ + public function set(string|int $key, mixed $value): void { $this->doSet($key, $value, false); } - public function add($element): bool + /** @param T $element */ + public function add(mixed $element): bool { return $this->doAdd($element, false); } @@ -438,18 +451,15 @@ public function isEmpty(): bool return $this->initialized ? $this->coll->isEmpty() : $this->count() === 0; } - /** - * @return Traversable - * @phpstan-return Traversable - */ - #[ReturnTypeWillChange] - public function getIterator() + /** @phpstan-return Traversable */ + public function getIterator(): Traversable { $this->initialize(); return $this->coll->getIterator(); } + /** @phpstan-return BaseCollection */ public function map(Closure $func): BaseCollection { $this->initialize(); @@ -457,6 +467,7 @@ public function map(Closure $func): BaseCollection return $this->coll->map($func); } + /** @phpstan-return BaseCollection */ public function filter(Closure $p): BaseCollection { $this->initialize(); @@ -539,13 +550,8 @@ public function __sleep(): array /* ArrayAccess implementation */ - /** - * @param mixed $offset - * - * @return bool - */ - #[ReturnTypeWillChange] - public function offsetExists($offset) + /** @param TKey $offset */ + public function offsetExists(mixed $offset): bool { $this->initialize(); @@ -553,13 +559,12 @@ public function offsetExists($offset) } /** - * @param mixed $offset + * @param TKey $offset * - * @return mixed * @phpstan-return T|null */ #[ReturnTypeWillChange] - public function offsetGet($offset) + public function offsetGet(mixed $offset): ?object { $this->initialize(); @@ -567,13 +572,10 @@ public function offsetGet($offset) } /** - * @param mixed $offset - * @param mixed $value - * - * @return void + * @param TKey $offset + * @param T|null $value */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) + public function offsetSet(mixed $offset, mixed $value): void { if (! isset($offset)) { $this->doAdd($value, true); @@ -584,9 +586,8 @@ public function offsetSet($offset, $value) $this->doSet($offset, $value, true); } - /** @return void */ - #[ReturnTypeWillChange] - public function offsetUnset(mixed $offset) + /** @param TKey $offset */ + public function offsetUnset(mixed $offset): void { $this->doRemove($offset, true); } @@ -647,11 +648,9 @@ public function __clone(): void /** * Actual logic for adding an element to the collection. * - * @param mixed $value - * - * @return true + * @param T $value */ - private function doAdd($value, bool $arrayAccess): true + private function doAdd(object $value, bool $arrayAccess): true { /* Initialize the collection before calling add() so this append operation * uses the appropriate key. Otherwise, we risk overwriting original data @@ -674,6 +673,8 @@ private function doAdd($value, bool $arrayAccess): true /** * Actual logic for removing element by its key. * + * @param TKey $offset + * * @return bool|T|null * @phpstan-return ( * $arrayAccess is false @@ -681,7 +682,7 @@ private function doAdd($value, bool $arrayAccess): true * : T|true|null * ) */ - private function doRemove(mixed $offset, bool $arrayAccess): bool|object|null + private function doRemove(string|int $offset, bool $arrayAccess): bool|object|null { $this->initialize(); if ($arrayAccess) { @@ -703,10 +704,10 @@ private function doRemove(mixed $offset, bool $arrayAccess): bool|object|null /** * Actual logic for setting an element in the collection. * - * @param mixed $offset - * @param mixed $value + * @param TKey $offset + * @param T|null $value */ - private function doSet($offset, $value, bool $arrayAccess): void + private function doSet(string|int $offset, ?object $value, bool $arrayAccess): void { $arrayAccess ? $this->coll->offsetSet($offset, $value) : $this->coll->set($offset, $value); From 8fbab2963bcd5f596a0217dc7a641ba051cf2c44 Mon Sep 17 00:00:00 2001 From: Krzysztof Ciszewski Date: Sun, 30 Nov 2025 15:27:50 +0100 Subject: [PATCH 4/6] revert docblock --- src/PersistentCollection/PersistentCollectionTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PersistentCollection/PersistentCollectionTrait.php b/src/PersistentCollection/PersistentCollectionTrait.php index 4eefc4297d..ed751e600f 100644 --- a/src/PersistentCollection/PersistentCollectionTrait.php +++ b/src/PersistentCollection/PersistentCollectionTrait.php @@ -386,7 +386,7 @@ public function exists(Closure $p): bool * @param T $element * @phpstan-return (TMaybeContained is T ? TKey|false : false) * - * @phpstan-template TMaybeContained + * @template TMaybeContained */ public function indexOf(mixed $element): string|int|false { From 94e914a6466c27cad4218801252f18fbad707edf Mon Sep 17 00:00:00 2001 From: Krzysztof Ciszewski Date: Sun, 30 Nov 2025 15:31:21 +0100 Subject: [PATCH 5/6] phpcs fix --- src/PersistentCollection/PersistentCollectionTrait.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/PersistentCollection/PersistentCollectionTrait.php b/src/PersistentCollection/PersistentCollectionTrait.php index ed751e600f..f3a5b7558a 100644 --- a/src/PersistentCollection/PersistentCollectionTrait.php +++ b/src/PersistentCollection/PersistentCollectionTrait.php @@ -12,7 +12,6 @@ use Doctrine\ODM\MongoDB\MongoDBException; use Doctrine\ODM\MongoDB\UnitOfWork; use Doctrine\ODM\MongoDB\Utility\CollectionHelper; -use ReturnTypeWillChange; use Traversable; use function array_combine; @@ -384,6 +383,7 @@ public function exists(Closure $p): bool /** * @param T $element + * * @phpstan-return (TMaybeContained is T ? TKey|false : false) * * @template TMaybeContained @@ -563,7 +563,6 @@ public function offsetExists(mixed $offset): bool * * @phpstan-return T|null */ - #[ReturnTypeWillChange] public function offsetGet(mixed $offset): ?object { $this->initialize(); From d8763106f3a0080a75f38e4cdb7aac74f0d3daa6 Mon Sep 17 00:00:00 2001 From: Krzysztof Ciszewski Date: Sun, 30 Nov 2025 16:40:39 +0100 Subject: [PATCH 6/6] fix phpstan --- .../PersistentCollectionTrait.php | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/PersistentCollection/PersistentCollectionTrait.php b/src/PersistentCollection/PersistentCollectionTrait.php index f3a5b7558a..ec003ae1b3 100644 --- a/src/PersistentCollection/PersistentCollectionTrait.php +++ b/src/PersistentCollection/PersistentCollectionTrait.php @@ -363,7 +363,7 @@ public function containsKey(string|int $key): bool } /** - * @param T $element + * @param TMaybeContained $element * * @template TMaybeContained */ @@ -382,7 +382,7 @@ public function exists(Closure $p): bool } /** - * @param T $element + * @param TMaybeContained $element * * @phpstan-return (TMaybeContained is T ? TKey|false : false) * @@ -459,7 +459,13 @@ public function getIterator(): Traversable return $this->coll->getIterator(); } - /** @phpstan-return BaseCollection */ + /** + * @phpstan-param Closure(T):U $func + * + * @phpstan-return BaseCollection + * + * @template U + */ public function map(Closure $func): BaseCollection { $this->initialize(); @@ -570,10 +576,6 @@ public function offsetGet(mixed $offset): ?object return $this->coll->offsetGet($offset); } - /** - * @param TKey $offset - * @param T|null $value - */ public function offsetSet(mixed $offset, mixed $value): void { if (! isset($offset)) { @@ -647,9 +649,9 @@ public function __clone(): void /** * Actual logic for adding an element to the collection. * - * @param T $value + * @param T|null $value */ - private function doAdd(object $value, bool $arrayAccess): true + private function doAdd(?object $value, bool $arrayAccess): true { /* Initialize the collection before calling add() so this append operation * uses the appropriate key. Otherwise, we risk overwriting original data