Skip to content

Commit c107652

Browse files
authored
Add Type::chunkArray()
1 parent 3e5195b commit c107652

19 files changed

+147
-68
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,11 +1283,6 @@ parameters:
12831283
count: 4
12841284
path: src/Type/ObjectWithoutClassType.php
12851285

1286-
-
1287-
message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#"
1288-
count: 1
1289-
path: src/Type/Php/ArrayChunkFunctionReturnTypeExtension.php
1290-
12911286
-
12921287
message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#"
12931288
count: 2

src/Type/Accessory/AccessoryArrayListType.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ public function getValuesArray(): Type
194194
return $this;
195195
}
196196

197+
public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
198+
{
199+
return $this;
200+
}
201+
197202
public function fillKeysArray(Type $valueType): Type
198203
{
199204
return new MixedType();

src/Type/Accessory/HasOffsetType.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ public function unsetOffset(Type $offsetType): Type
175175
return $this;
176176
}
177177

178+
public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
179+
{
180+
return new NonEmptyArrayType();
181+
}
182+
178183
public function fillKeysArray(Type $valueType): Type
179184
{
180185
return new NonEmptyArrayType();

src/Type/Accessory/HasOffsetValueType.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@ public function getValuesArray(): Type
209209
return new NonEmptyArrayType();
210210
}
211211

212+
public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
213+
{
214+
return new NonEmptyArrayType();
215+
}
216+
212217
public function fillKeysArray(Type $valueType): Type
213218
{
214219
return new NonEmptyArrayType();

src/Type/Accessory/NonEmptyArrayType.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,11 @@ public function getValuesArray(): Type
179179
return $this;
180180
}
181181

182+
public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
183+
{
184+
return $this;
185+
}
186+
182187
public function fillKeysArray(Type $valueType): Type
183188
{
184189
return $this;

src/Type/Accessory/OversizedArrayType.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ public function getValuesArray(): Type
175175
return $this;
176176
}
177177

178+
public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
179+
{
180+
return $this;
181+
}
182+
178183
public function fillKeysArray(Type $valueType): Type
179184
{
180185
return $this;

src/Type/ArrayType.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,20 @@ public function unsetOffset(Type $offsetType): Type
513513
return $this;
514514
}
515515

516+
public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
517+
{
518+
$chunkType = $preserveKeys->yes()
519+
? $this
520+
: AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $this->getIterableValueType()));
521+
$chunkType = TypeCombinator::intersect($chunkType, new NonEmptyArrayType());
522+
523+
$arrayType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $chunkType));
524+
525+
return $this->isIterableAtLeastOnce()->yes()
526+
? TypeCombinator::intersect($arrayType, new NonEmptyArrayType())
527+
: $arrayType;
528+
}
529+
516530
public function fillKeysArray(Type $valueType): Type
517531
{
518532
$itemType = $this->getItemType();

src/Type/Constant/ConstantArrayType.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class ConstantArrayType extends ArrayType implements ConstantType
7373
{
7474

7575
private const DESCRIBE_LIMIT = 8;
76+
private const CHUNK_FINITE_TYPES_LIMIT = 5;
7677

7778
private TrinaryLogic $isList;
7879

@@ -780,6 +781,36 @@ public function unsetOffset(Type $offsetType): Type
780781
return new self($this->keyTypes, $this->valueTypes, $this->nextAutoIndexes, $optionalKeys, $isList);
781782
}
782783

784+
public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
785+
{
786+
$biggerOne = IntegerRangeType::fromInterval(1, null);
787+
$finiteTypes = $lengthType->getFiniteTypes();
788+
if ($biggerOne->isSuperTypeOf($lengthType)->yes() && count($finiteTypes) < self::CHUNK_FINITE_TYPES_LIMIT) {
789+
$results = [];
790+
foreach ($finiteTypes as $finiteType) {
791+
if (!$finiteType instanceof ConstantIntegerType || $finiteType->getValue() < 1) {
792+
return parent::chunkArray($lengthType, $preserveKeys);
793+
}
794+
795+
$length = $finiteType->getValue();
796+
797+
$builder = ConstantArrayTypeBuilder::createEmpty();
798+
799+
$keyTypesCount = count($this->keyTypes);
800+
for ($i = 0; $i < $keyTypesCount; $i += $length) {
801+
$chunk = $this->slice($i, $length, true);
802+
$builder->setOffsetValueType(null, $preserveKeys->yes() ? $chunk : $chunk->getValuesArray());
803+
}
804+
805+
$results[] = $builder->getArray();
806+
}
807+
808+
return TypeCombinator::union(...$results);
809+
}
810+
811+
return parent::chunkArray($lengthType, $preserveKeys);
812+
}
813+
783814
public function fillKeysArray(Type $valueType): Type
784815
{
785816
$builder = ConstantArrayTypeBuilder::createEmpty();
@@ -1185,7 +1216,10 @@ public function reverse(bool $preserveKeys = false): self
11851216
return $this->reverseConstantArray(TrinaryLogic::createFromBoolean($preserveKeys));
11861217
}
11871218

1188-
/** @param positive-int $length */
1219+
/**
1220+
* @deprecated Use chunkArray() instead
1221+
* @param positive-int $length
1222+
*/
11891223
public function chunk(int $length, bool $preserveKeys = false): self
11901224
{
11911225
$builder = ConstantArrayTypeBuilder::createEmpty();

src/Type/IntersectionType.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,11 @@ public function getValuesArray(): Type
724724
return $this->intersectTypes(static fn (Type $type): Type => $type->getValuesArray());
725725
}
726726

727+
public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
728+
{
729+
return $this->intersectTypes(static fn (Type $type): Type => $type->chunkArray($lengthType, $preserveKeys));
730+
}
731+
727732
public function fillKeysArray(Type $valueType): Type
728733
{
729734
return $this->intersectTypes(static fn (Type $type): Type => $type->fillKeysArray($valueType));

src/Type/MixedType.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,15 @@ public function getValuesArray(): Type
189189
return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new MixedType($this->isExplicitMixed)));
190190
}
191191

192+
public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type
193+
{
194+
if ($this->isArray()->no()) {
195+
return new ErrorType();
196+
}
197+
198+
return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new MixedType($this->isExplicitMixed)));
199+
}
200+
192201
public function fillKeysArray(Type $valueType): Type
193202
{
194203
if ($this->isArray()->no()) {

0 commit comments

Comments
 (0)