|
| 1 | +# Type Safety with Generics |
| 2 | + |
| 3 | +Pipeline uses PHP's generic types (`@template` in PHPDocs) to provide robust type safety. This enhances static analysis (PHPStan, Psalm), leading to more reliable code. |
| 4 | + |
| 5 | +## How It Works |
| 6 | + |
| 7 | +The `Pipeline\Standard` class uses generic types to inform static analysis tools about the types of keys (`TKey`) and values (`TValue`) in your pipeline. |
| 8 | + |
| 9 | +## Using Type-Safe Pipelines |
| 10 | + |
| 11 | +### Type Inference |
| 12 | + |
| 13 | +Pipeline often infers types automatically when creating pipelines using functions like `fromValues()` or `fromArray()`. |
| 14 | + |
| 15 | +```php |
| 16 | +use function Pipeline\fromArray; |
| 17 | +use function Pipeline\fromValues; |
| 18 | + |
| 19 | +$strings = fromValues('hello', 'world'); // Inferred: Standard<int, string> |
| 20 | +$numbers = fromArray(['a' => 1, 'b' => 2]); // Inferred: Standard<string, int> |
| 21 | +``` |
| 22 | + |
| 23 | +Explicit PHPDoc type annotations can be added if needed: |
| 24 | + |
| 25 | +```php |
| 26 | +/** @var Standard<int, string> $strings */ |
| 27 | +$strings = fromValues('hello', 'world'); |
| 28 | +``` |
| 29 | + |
| 30 | +### Type Transformations |
| 31 | + |
| 32 | +* **`filter()`**: This method preserves the existing types of elements, only reducing their count. |
| 33 | + ```php |
| 34 | + $pipeline = fromValues('hello', 'world')->filter(fn($s) => strlen($s) > 4); |
| 35 | + // Result: list<string> |
| 36 | + ``` |
| 37 | +* **`map()` / `cast()`**: These methods are used to transform values, potentially changing their types. Static analysis tools accurately track these type changes. |
| 38 | + ```php |
| 39 | + $pipeline = fromArray(['a' => 1])->map(fn($n) => "Number: $n"); |
| 40 | + // Result: array<string, string> |
| 41 | + ``` |
| 42 | +* **`reduce()` / `fold()`**: Aggregation methods like `reduce()` and `fold()` also benefit from type checking, ensuring type safety for accumulators and elements. |
| 43 | + |
| 44 | +### Extracting Data |
| 45 | + |
| 46 | +Terminal operations such as `toList()` and `toAssoc()` extract processed data into standard PHP arrays, with types correctly inferred by static analysis. |
| 47 | + |
| 48 | +```php |
| 49 | +use function Pipeline\take; |
| 50 | + |
| 51 | +$data = take($someIterable); |
| 52 | +$list = $data->toList(); // Numerically indexed |
| 53 | +$assoc = $data->toAssoc(); // Associative |
| 54 | +``` |
| 55 | + |
| 56 | +## Important Considerations |
| 57 | + |
| 58 | +* **Mutability**: Pipeline instances are mutable; methods like `map()` modify the *same* instance. |
| 59 | +* **One-Time Use**: As with PHP generators, pipelines are generally one-time use; after a terminal operation (e.g., `toList()`), the pipeline is exhausted. |
| 60 | +* **Complex Transformations**: Operations such as `chunk()`, `flip()`, `values()`, and `keys()` inherently alter the key/value relationships within the pipeline. Due to these complex transformations, explicit type hints may occasionally be necessary to assist static analysis tools. |
| 61 | + ```php |
| 62 | + use Pipeline\Standard; |
| 63 | + /** @var Standard<int, string> $pipeline */ |
| 64 | + $pipeline = fromArray(['a' => 1])->flip(); |
| 65 | + ``` |
| 66 | +* **Backward Compatibility**: All type improvements are implemented purely through PHPDoc comments, ensuring no runtime impact and 100% backward compatibility. This design principle is consistent across the library. |
| 67 | + |
| 68 | +## Tool Setup & Tips |
| 69 | + |
| 70 | +* **PHPStan/Psalm**: Include Pipeline in your project. Configure a high analysis level. |
| 71 | +* **Tips**: |
| 72 | + * Provide type hints when the source isn't obvious. |
| 73 | + * Prefer arrow functions for better type inference. |
| 74 | + * Integrate static analysis into your CI pipeline. |
| 75 | + |
| 76 | +The Pipeline type system is designed to be a helpful tool, providing robust static analysis. |
0 commit comments