## Les Exceptions : ### Le trou dans la raquette du typage
- Baptiste Langlade - Lyon - Efalia - ~10 ans XP - ~80 packages open source
$f = fn(InputType $x): OutputType => $y;
```php function getUser(string $id): User; function createUser(string $email): User; ``` Note: lecture vs écriture
`\Throwable` `\Exception` `\Error` Note: monde imparfait
```php class UserNotFound extends \RuntimeException {} ``` Note: abscence de donnée
```php class InvalidEmail extends \DomainException {} ``` Note: structure de controle
## Uniformité Note: dans tout le language
## Analyse statique Note: vérification non automatisable phpstan/psalm check I/O mais pas les exceptions
``` Controller -> Service1 -> Service2 -> getUser() ``` Note: qui catch ? catch intermédiaire => code mort ? nouvelle exception ?
## Alternatives
```php function getUser(string $id): ?User; ``` Note: marche pas pour l'écriture
```php [$error, $user] = getUser($id); ``` Note: Go lang uniforme mais implique un if
## Typage Note: le point commun on ramène les erreurs dans le système de typage
## Monad Note: erreur dans typage + uniformité + simplicité (continuité)

Maybe

Either

Set

Sequence

State

IO

Free

...

Maybe

Either

Avant

Après

Avant

Après

function userController(string $id): Response {
    return getUser($id)->match(
        fn(User $user) => new Response($user->toArray()),
        fn() => new Response(null, 404),
    );
}
                        
function userController(string $id): Response {
    return getUser($id)
        ->map(fn(User $user) => $user->toArray())
        ->match(
            fn(array $data) => new Response($data),
            fn() => new Response(null, 404),
        );
}
                        
function brotherController(string $id): Response {
    return getUser($id)
        ->map(fn(User $user) => $user->getBrother())
        ->map(fn(User $brother) => $brother->toArray())
        ->match(
            fn(array $data) => new Response($data),
            fn() => new Response(null, 404),
        );
}
                        
function brotherController(string $id): Response {
    return getUser($id)
        ->map(fn(User $user) => $user->getBrotherId())
        ->flatMap(fn(string $brotherId) => getUser($brotherId))
        ->map(fn(User $brother) => $brother->toArray())
        ->match(
            fn(array $data) => new Response($data),
            fn() => new Response(null, 404),
        );
}
                        
function brotherController(string $id): Response {
    return getUser($id)
        ->map(fn(User $user) => $user->getBrotherId())
        ->flatMap(fn(string $brotherId) => getUser($brotherId))
        ->map(fn(User $user) => $user->toArray())
        ->match(
            fn(array $data) => new Response($data),
            fn() => new Response(null, 404),
        );
}
                        

Avant

Après

Avant

Après

## Monad - `map` - `flatMap` Note: mention spéciale : Promises, then = map + flatMap
## Migration
```php class UserRepository { public function get(string $id): Maybe; } ``` ```php # ServiceClass $user = $userRepository->get($id)->match( fn(User $user) => $user, fn() => throw new UserNotFound(), ); ```
### Supprimer toutes les exceptions ?
```sh composer require innmind/immutable ```
# Questions ![](joind.png) Twitter @Baptouuuu Github @Baptouuuu/talks