Декларация возвращаемого типа Symfony3 и PHP 7 для методов репозитория Doctrine

Мне очень нравятся объявления возвращаемого типа в PHP, и я хочу использовать их в Symfony 3.

Все методы контроллера должны возвращать объект Response, в этом нет проблем. Однако в репозиториях Doctrine Doctrine может возвращать объект Entity или null.

Рассмотрим этот пример:

  • Вы создали простую сущность Post.
  • Вы создали собственный метод findByName в PostRepository:

PostRepository.php

public function findByName($name) : Post
{
    $qb = $this->createQueryBuilder('p')
        ->where('p.name = :name')
        ->setParameter('name', $name);

    $post = $qb->getQuery()->getOneOrNullResult();

    return (null === $post) ? new Post() : $post;
}

Вы вызываете этот метод из контроллера, например:

DefaultController.php

/**
 * @Route("/", name="homepage")
 */
public function indexAction(Request $request)
{
    $em = $this->getDoctrine()->getManager();
    $repository = $em->getRepository('AppBundle:Post');

    try {
        $post = $repository->findByName('test');
    } catch (\TypeError $e) {
        $post = new Post();
    }

    return new Response(dump($post));
}

Я знаю, что попытка перехватить исключение не будет выполнена, потому что findByName() всегда возвращает объект Post.

Мой вопрос: где мы должны обрабатывать исключение? Согласно этому ответу, лучше бросить исключение. Должны ли мы гарантировать, что метод репозитория вообще не выдает исключение, используя это:

$post = $qb->getQuery()->getOneOrNullResult();

return (null === $post) ? new Post() : $post;

или позволить PHP генерировать исключение TypeError и позволить контроллеру обработать его?

Doctrine создает исключения для методов getOneOrNullResult() и getSingleResult(), как описано здесь.

Если этот сценарий не имеет смысла, потому что лучше позволить вашему контроллеру обрабатывать исключение и возвращать страницу «не найдено», потому что сообщение не существует, как это:

return $this->createNotFoundException();

Сценарий №2

Post существует в базе данных, и вызывается другой метод репозитория, getApprovedComments(), комментарии не возвращаются, мы ожидаем ArrayCollection, но получаем array. Это вызовет исключение PHP TypeError.

Я думаю, что код будет полон блоков try/catch. Можно ли обрабатывать такого рода исключения на более высоком уровне, чтобы в коде было меньше блоков try/catch?

На первый взгляд, это не лучшее решение, потому что код должен быть достаточно гибким, чтобы перехватывать каждое исключение TypeError и предпринимать правильные действия по отображению страницы.


person ABC    schedule 21.02.2016    source источник
comment
Что бы вы ни делали, вы абсолютно не должны ловить ошибки типа или любые другие ошибки в этом отношении. Если возникает ошибка, это означает ошибку программирования, которую необходимо устранить, избегая условий, которые приводят к возникновению ошибки. Это в значительной степени цель различия ошибок и исключений. Вы должны когда-либо перехватывать ошибки только в своем обработчике исключений верхнего уровня или если вы находитесь в какой-то действительно конкретной, действительно особой ситуации.   -  person NikiC    schedule 22.02.2016
comment
@NikiC спасибо, но это означает, что пользователь увидит исключение во внешнем интерфейсе сайта, потому что запрос к базе данных не дал ожидаемых результатов? Если ошибки скрыты, пользователь просто увидит страницу с ошибкой? Подводя итог, мне нужно убедиться, что метод всегда возвращает правильный тип, несмотря ни на что. Можете ли вы предоставить какие-либо официальные источники, подтверждающие ваше заявление, пожалуйста?   -  person ABC    schedule 22.02.2016
comment
Вы должны знать, что методы действия контроллера Symfony не обязаны возвращать объект ответа и часто этого не делают. Это только мое мнение, но я думаю, что вы, возможно, слишком усложняете вещи.   -  person Cerad    schedule 22.02.2016
comment
@Cerad в соответствии с документами. Контроллер – это создаваемый вами PHP-вызов, который принимает информация из HTTP-запроса и создает и возвращает HTTP-ответ (как объект ответа Symfony). Если метод действия контроллера не возвращает объект Response, возникает исключение LogicException с этим сообщением: Контроллер должен вернуть ответ (нуль дан). Вы забыли добавить оператор возврата куда-нибудь в свой контроллер?   -  person ABC    schedule 22.02.2016
comment
Похоже, документы нужно немного подправить. Обработчик запросов проверяет результаты вызова действия контроллера. Если это не ответ, то он отправляет результаты слушателю, который, в свою очередь, может генерировать ответ. Вот как, например, работает директива sensio @template: symfony. com/doc/current/bundles/SensioFrameworkExtraBundle/. Как видите, контроллер возвращает массив. Это, кстати, одна из причин, по которой я обычно рекомендую создать несколько приложений, прежде чем пытаться слишком много настраивать.   -  person Cerad    schedule 22.02.2016
comment
Я понимаю что ты имеешь ввиду. Я забыл, что аннотация @Template возвращает array. В этом случае этот конкретный метод действия контроллера будет иметь array в качестве объявления типа возвращаемого значения.   -  person ABC    schedule 23.02.2016