Skip to content

Commit 5b490e4

Browse files
committed
Add with method
1 parent 4112a11 commit 5b490e4

5 files changed

Lines changed: 121 additions & 12 deletions

File tree

doc/Arr.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,22 @@ $spliced = $arr->toSpliced(1, 2, 100);
498498

499499
---
500500

501+
### `with(int $index, mixed $value): self`
502+
503+
Returns a new array with the element at `index` replaced by `value` (does not modify the original). Supports negative indices.
504+
505+
```php
506+
$arr = new Arr(1, 2, 3, 4, 5);
507+
$result = $arr->with(2, 99);
508+
// $result is [1, 2, 99, 4, 5], $arr is [1, 2, 3, 4, 5]
509+
510+
$arr2 = new Arr(1, 2, 3);
511+
$result2 = $arr2->with(-1, 'x');
512+
// $result2 is [1, 2, 'x']
513+
```
514+
515+
---
516+
501517
### `toString(): string`
502518

503519
Returns a string representation by joining with `','`.

infection.json

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@
3535
"Chubbyphp\\Typescript\\Arr::reduceRight::601",
3636
"Chubbyphp\\Typescript\\Arr::slice::674",
3737
"Chubbyphp\\Typescript\\Arr::some::714",
38-
"Chubbyphp\\Typescript\\Arr::toSpliced::876"
38+
"Chubbyphp\\Typescript\\Arr::toSpliced::876",
39+
"Chubbyphp\\Typescript\\Arr::with::907"
3940
]
4041
},
4142
"GreaterThan": {
4243
"ignore": [
43-
"Chubbyphp\\Typescript\\Arr::mixedToString::994",
44+
"Chubbyphp\\Typescript\\Arr::mixedToString::1021",
4445
"Chubbyphp\\Typescript\\Arr::slice::681",
4546
"Chubbyphp\\Typescript\\Arr::slice::685",
4647
"Chubbyphp\\Typescript\\Arr::splice::755",
@@ -64,13 +65,16 @@
6465
"Chubbyphp\\Typescript\\Arr::map::495",
6566
"Chubbyphp\\Typescript\\Arr::reduce::558",
6667
"Chubbyphp\\Typescript\\Arr::reduce::573",
67-
"Chubbyphp\\Typescript\\Arr::some::714"
68+
"Chubbyphp\\Typescript\\Arr::some::714",
69+
"Chubbyphp\\Typescript\\Arr::with::896",
70+
"Chubbyphp\\Typescript\\Arr::with::900",
71+
"Chubbyphp\\Typescript\\Arr::with::907"
6872
]
6973
},
7074
"LogicalAndSingleSubExprNegation": {
7175
"ignore": [
72-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1024",
73-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1028"
76+
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1051",
77+
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1055"
7478
]
7579
},
7680
"Minus": {
@@ -87,13 +91,13 @@
8791
"ReturnRemoval": {
8892
"ignore": [
8993
"Chubbyphp\\Typescript\\Arr::lastIndexOf::464",
90-
"Chubbyphp\\Typescript\\Arr::offsetSet::968",
91-
"Chubbyphp\\Typescript\\Arr::offsetSet::972",
92-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1025",
93-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1029",
94-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1032",
95-
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1035"
94+
"Chubbyphp\\Typescript\\Arr::offsetSet::995",
95+
"Chubbyphp\\Typescript\\Arr::offsetSet::999",
96+
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1052",
97+
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1056",
98+
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1059",
99+
"Chubbyphp\\Typescript\\Arr::strictlyEqual::1062"
96100
]
97101
}
98102
}
99-
}
103+
}

src/Arr.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,33 @@ public function toSpliced(int $start, ?int $deleteCount = null, mixed ...$items)
884884
return $result;
885885
}
886886

887+
/**
888+
* @param T $value
889+
*
890+
* @return self<T>
891+
*/
892+
public function with(int $index, mixed $value): self
893+
{
894+
$len = $this->internalLength;
895+
896+
if ($index < 0) {
897+
$index = $len + $index;
898+
}
899+
900+
if ($index < 0 || $index >= $len) {
901+
throw new RangeError('Invalid index: '.$index);
902+
}
903+
904+
/** @var self<T> $result */
905+
$result = new self($this->internalLength);
906+
907+
for ($i = 0; $i < $len; ++$i) {
908+
$result->internalArray[$i] = ($i === $index) ? $value : ($this->internalArray[$i] ?? null);
909+
}
910+
911+
return $result;
912+
}
913+
887914
public function toString(): string
888915
{
889916
return $this->join();

tests/Integration/DocumentationExamplesTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,20 @@ public function testDocToSplicedExample(): void
358358
self::assertSame([1, 2, 3, 4], $arr->toArray());
359359
}
360360

361+
public function testDocWithExample(): void
362+
{
363+
$arr = new Arr(1, 2, 3, 4, 5);
364+
$result = $arr->with(2, 99);
365+
366+
self::assertSame([1, 2, 99, 4, 5], $result->toArray());
367+
self::assertSame([1, 2, 3, 4, 5], $arr->toArray());
368+
369+
$arr2 = new Arr(1, 2, 3);
370+
$result2 = $arr2->with(-1, 'x');
371+
372+
self::assertSame([1, 2, 'x'], $result2->toArray());
373+
}
374+
361375
public function testDocToStringExample(): void
362376
{
363377
$arr = new Arr(1, 2, 3);

tests/Unit/ArrTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2799,6 +2799,54 @@ public function testToSplicedWithExplicitNullDeleteCountReturnsUnchangedCopy():
27992799
self::assertSame([0, 1, 2, 3], iterator_to_array($array->values()));
28002800
}
28012801

2802+
// Array.prototype.with
2803+
2804+
public function testWithReplacesElementAtPositiveIndex(): void
2805+
{
2806+
self::assertSame([1, 2, 99, 4, 5], iterator_to_array((new Arr(1, 2, 3, 4, 5))->with(2, 99)->values()));
2807+
}
2808+
2809+
public function testWithReplacesElementAtNegativeIndex(): void
2810+
{
2811+
self::assertSame([1, 2, 'x'], iterator_to_array((new Arr(1, 2, 3))->with(-1, 'x')->values()));
2812+
}
2813+
2814+
public function testWithDoesNotModifyOriginalArray(): void
2815+
{
2816+
$array = new Arr(1, 2, 3);
2817+
$result = $array->with(1, 99);
2818+
2819+
self::assertNotSame($array, $result);
2820+
self::assertSame([1, 2, 3], iterator_to_array($array->values()));
2821+
self::assertSame([1, 99, 3], iterator_to_array($result->values()));
2822+
}
2823+
2824+
public function testWithThrowsRangeErrorForOutOfBoundsIndex(): void
2825+
{
2826+
$this->expectException(RangeError::class);
2827+
$this->expectExceptionMessage('Invalid index: 10');
2828+
2829+
(new Arr(1, 2, 3))->with(10, 'x');
2830+
}
2831+
2832+
public function testWithThrowsRangeErrorForEmptyArray(): void
2833+
{
2834+
$this->expectException(RangeError::class);
2835+
$this->expectExceptionMessage('Invalid index: 0');
2836+
2837+
(new Arr())->with(0, 'x');
2838+
}
2839+
2840+
public function testWithReplacesHoleInSparseArray(): void
2841+
{
2842+
$array = new Arr(5);
2843+
$array[2] = 'present';
2844+
2845+
$result = $array->with(3, 'filled');
2846+
2847+
self::assertSame('filled', $result->at(3));
2848+
}
2849+
28022850
// Array.prototype.toString
28032851

28042852
public function testToStringReturnsEmptyStringForEmptyArray(): void

0 commit comments

Comments
 (0)