lstrojny/functional-php
Functional PHP adds a rich set of functional programming helpers for PHP: map/filter/reduce, partial application, currying, composition, and collections utilities. Write cleaner, more declarative code without changing your framework or coding style.
Maybe, Either, Result, Try, Validation) to PHP, which aligns well with modern Laravel applications leveraging dependency injection, immutability, and declarative patterns. It complements Laravel’s service container and Eloquent’s query builder by enabling explicit error handling and composable workflows without side effects.Result/Validation can encapsulate domain logic outcomes (e.g., UserRegistrationResult) and Either can model invariants (e.g., Either<ValidationError, User>).try-catch with Try monads or null checks with Maybe).Try for service-layer operations).pipe()) can replace nested closures in middleware or form requests.Maybe/Result to handle null or validation failures (e.g., User::findOrFail() → UserRepository::findById() returning Result).Validation objects for input rules) and mocking side effects via Try.Validator).Maybe wrappers). Benchmark critical paths (e.g., API request handlers) post-integration.Maybe<User>) may require custom PHPDoc or static analysis rules.Http\Requests or Console\Commands (would need custom wrappers).Exception handling (e.g., Try vs. try-catch).throw new \Exception) or supplement it?Result/Either integrate with Laravel’s App\Exceptions\Handler (e.g., converting ValidationError to HTTP responses)?Maybe::just() vs. null)?pipe($request, validate(), process(), save())).Result<User> or Either<Error, User[]> instead of raw collections or exceptions.Try to wrap side effects (e.g., Try::of(fn() => $this->authService->validate())).Result for optimistic UI updates.Maybe to handle empty queries gracefully.{"data": null, "error": "Invalid email"} for Either) and map to frontend state (e.g., React’s useReducer).NewsletterService).try-catch blocks with Try for external API calls.Validation for form requests instead of Laravel’s Validator facade.App\Contracts\ResultHandler).Result (e.g., UserRepository::create()).Try or Maybe (e.g., AuthenticateUserMiddleware).Result/Either into Laravel responses (e.g., Response::json($result->unwrapOrFail())).Validation for DTO validation in API resources.assertTrue($result->isSuccess())).Either::left()).Result (e.g., ExceptionAdapter::toResult()).Maybe<User>).| Phase | Focus Area | Risks Mitigated |
|---|---|---|
| 1. Proof of Concept | Single service/module | Team learning curve, minimal disruption |
| 2. Service Layer | Repositories/services | Error handling consistency |
| 3. API Layer | Request/response transformations | Frontend-backend alignment |
| 4. Testing | Refactor tests for functional types | Regression safety |
| 5. Full Adoption | Middleware, Eloquent, Console | Performance, team proficiency |
Result/Either forces clear error paths, reducing null/try-catch spaghetti.pipe(), tap()) simplify complex workflows (e.g., data processing).Maybe/Result adds verbosity (mitigate with helper traits).Try/Either may be less intuitive than exceptions (log unwrap() calls).Maybe vs. Either vs. Result.Result in repositories).ValidationError or Try::failure() instead of exceptions.logger->info($result->toString())).Maybe).Try::of(fn() => $heavyOperation)).cache()->remember('key', fn() => Try::of($expensiveCall))).Try integrate with Laravel Queues (e.g., Try::of(fn() => $job->handle())).Result for job outcomes.| Scenario | Functional Pattern Solution | Laravel-Specific Risk |
|---|---|---|
| Null values | Maybe::just($value) or Maybe::nothing() |
Eloquent null results → Maybe::nothing() |
| Validation failures | Validation::fail("error") |
Laravel Validator → custom Validation adapter |
| External API failures | `Try::failure(new \RuntimeException |
How can I help you explore Laravel packages today?