phpstan-doctrine: QueryBuilder Result returns mixed when created in another method

I’m still running into the https://github.com/phpstan/phpstan-doctrine/issues/266 issue, which I thought should be fixed with: https://github.com/phpstan/phpstan-doctrine/commit/149cf71c3b470f815ad8ad658606e9217db22d9f

But in my cases it ends still in mixed state.

I created a reproducer here:

git clone git@github.com:alexander-schranz/phpstan-query-builder-reproducer.git
cd phpstan-query-builder-reproducer/
composer install

vendor/bin/phpstan analyse

https://github.com/alexander-schranz/phpstan-query-builder-reproducer/blob/main/src/Repository/VisitorRepository.php

Output:

 ------ ----------------------------------------------------------------------------------------------------------
  Line   src/Repository/VisitorRepository.php
 ------ ----------------------------------------------------------------------------------------------------------
  46     Dumped type: mixed
  48     Method App\Repository\VisitorRepository::findBy() should return iterable<App\Entity\Visitor> but returns
         mixed.
  60     Dumped type: mixed
  62     Method App\Repository\VisitorRepository::findFlatBy() should return iterable<array{id: int, title:
         string|null}> but returns mixed.
  75     Dumped type: mixed
  77     Method App\Repository\VisitorRepository::findOneBy() should return App\Entity\Visitor|null but returns
         mixed.
  90     Dumped type: mixed
  92     Method App\Repository\VisitorRepository::getOneBy() should return App\Entity\Visitor but returns mixed.
 ------ ----------------------------------------------------------------------------------------------------------

Not sure what is different then to the test case 🤔

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 15 (3 by maintainers)

Most upvoted comments

I’m also running into this issue in a bleeding edge development environment, both with Symfony 6.2 and 6.3-beta.

Simple reproducer:

use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @extends ServiceEntityRepository<Unit>
 */
class UnitRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Unit::class);
    }

    /**
     * @return Unit[]
     */
    public function getUnits(): array
    {
        return $this->createQueryBuilder('u')->getQuery()->getResult();
    }
}

Gives:

  35     Method App\Repository\UnitRepository::getUnits() should return array<App\Entity\Unit> but returns mixed.

Notably this only occurs at level 9, it passes without issue on level 8. PHPStan documents level 9 as:

be strict about the mixed type - the only allowed operation you can do with it is to pass it to another mixed

Looking at https://github.com/phpstan/phpstan-doctrine/blob/1.3.x/stubs/ORM/QueryBuilder.stub#L17-L22 it would seem PHPStan is shooting its own foot - the stub is prescribing something that cannot pass level 9 by definition.

Hi! Is there a way to fix this without ignoring it?