Introduction Functional programming is old. But it did not become popular, and probably for a reason. It is sometimes quite hard to understand and use it. But it has a lot of advantages. One of them is the ability to avoid null-checking and exceptions. In this article, we will look at the Maybe monad and how to use it in Symfony. What is the Maybe monad? Let's start with the definition of monad itself. A monad is a structure that represents computations defined as sequences of steps. It is a generalization of the concept of a function that takes an argument and returns a result. A monad in functional programming is not something new. It has been around since the 1960s. The Maybe monad is a monad that encapsulates an optional value. A value of type contains either a value of type (represented as ) or nothing at all (represented as ). Using the Maybe monad, we can avoid null values and exceptions. Maybe a a Just a Nothing How to use the Maybe monad in Symfony? Let's create a Monad class that will implement the Maybe monad. // src/Utils/Maybe.php <?php namespace App\Utils; /** * @template T */ class Maybe { /** * @var T|null */ private $value; /** * @param T|null $value */ private function __construct($value) { $this->value = $value; } /** * @param T|null $value * @return Maybe<T> */ public static function just($value): Maybe { return new self($value); } /** * @return Maybe<T> */ public static function nothing(): Maybe { return new self(null); } /** * @template U * @param callable(T):U $fn * @return Maybe<U> */ public function map(callable $fn): Maybe { if ($this->value === null) { return self::nothing(); } return self::just($fn($this->value)); } /** * @param T $defaultValue * @return T */ public function getOrElse($defaultValue) { return $this->value ?? $defaultValue; } } The class has two static methods: and . The method creates a object with a value. Maybe just nothing just Maybe The method creates a object without a value. The method takes a function as an argument and applies it to the value inside the object. If the value inside the object is , the method returns . The method returns the value inside the object or a default value if the value inside the object is . nothing Maybe map Maybe Maybe null map nothing getOrElse Maybe Maybe null Let's check how to use it in the Symfony application. // src/Controller/DefaultController.php <?php namespace App\Controller; use App\Entity\User; use App\Service\UserSrvice; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; class DefaultController extends AbstractController { #[Route('', name: 'default')] public function getUserData(Request $request, UserSrvice $userSrvice): JsonResponse { $email = $request->get('email'); $maybeUser = $userSrvice->getUserByEmail($email); $userData = $maybeUser ->map(fn(User $user) => [ 'name' => $user->getName(), 'email' => $user->getEmail(), ]) ->getOrElse([ 'name' => 'Unknown', 'email' => 'Unavailable', ]) ; return $this->json($userData); } } // src/Service/UserSrvice.php <?php declare(strict_types=1); namespace App\Service; use App\Repository\UserRepository; use App\Utils\Maybe; class UserSrvice { public function __construct(private readonly UserRepository $userRepository) { } public function getUserByEmail(string $email): Maybe { return Maybe::just($this->userRepository->getUserByEmail($email)); } } In the class, we get the email from the request. Then we get the user by email using the class. DefaultController UserSrvice The class returns a object. We use the method to get the user data. If the user is not found, the method returns . UserSrvice Maybe map map nothing Then we use the method to get the user data or a default value if the user is not found. getOrElse Conclusion In this article, we looked at the Maybe monad and how to use it in Symfony. We created a class that implements the Maybe monad. We used the class in the class to avoid null-checking and exceptions. Using this approach, we can avoid null-checking and exceptions in our Symfony application, and the code will be more readable. Maybe Maybe DefaultController The full code is available on . GitHub