← All results

Collection<*> (star projection)

Group: Advanced PHPDoc types · Category: ecosystem · File: phpdoc_advanced_phpstan_star_projection.php

A PHPStan call-site variance spelling. * as a type argument means the function accepts a collection of *any* item type, and combines the write restriction of covariance (add() expects never) with the read restriction of contravariance (get() is mixed). It is not Collection<mixed>: an invariant Collection<mixed> still rejects Collection<int>. Mago implements it too. Psalm rejects * as InvalidDocblock and discards the whole annotation (vimeo/psalm#11931). References: - PHPStan phpdoc-types: Generics (Collection<*>) - PHPStan "A guide to call-site generic variance" (star projections) - psalm#11931

Analyzer results

AnalyzerVersionResultDiagnostics
phan 6.0.7Phan 6.0.7 php-ast version 1.1.3 PHP version used to run Phan: 8.5.9 Unrecognized
phpdoc_advanced_phpstan_star_projection.php:78: Saw possibly unextractable annotation for a fragment of comment '* @param Collection<*> $collection': after Collection, did not see an element name (will guess based on comment order) [PhanUnextractableAnnotationElementName]
phpdoc_advanced_phpstan_star_projection.php:78: Saw a token Phan may have failed to parse after '* @param Collection<*> $collection': after Collection, saw '<' [PhanUnextractableAnnotationSuffix]
phpdoc_advanced_phpstan_star_projection.php:86: Saw possibly unextractable annotation for a fragment of comment '* @param Collection<*> $collection': after Collection, did not see an element name (will guess based on comment order) [PhanUnextractableAnnotationElementName]
phpdoc_advanced_phpstan_star_projection.php:86: Saw a token Phan may have failed to parse after '* @param Collection<*> $collection': after Collection, saw '<' [PhanUnextractableAnnotationSuffix]
  • Recognition: spelling not resolved — reported on declaration line(s) 78, 86
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved

Notes: Cannot extract the annotation after `Collection` (`PhanUnextractableAnnotationElementName` / `Suffix` on `Collection<*>`), so the spelling is not parsed and add() is unrestricted.

phpstan 2.2.15PHPStan - PHP Static Analysis Tool 2.2.15 Enforced reported Lv.5+
phpdoc_advanced_phpstan_star_projection.php:90: Parameter #1 $item of method Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<*>::add() expects never, int given. [reported-from-level=5]
phpdoc_advanced_phpstan_star_projection.php:115: Parameter #1 $collection of function Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\takesMixed expects Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<mixed>, Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<int> given. [reported-from-level=9]
With strict-rules
phpdoc_advanced_phpstan_star_projection.php:90: Parameter #1 $item of method Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<*>::add() expects never, int given.
phpdoc_advanced_phpstan_star_projection.php:115: Parameter #1 $collection of function Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\takesMixed expects Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<mixed>, Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<int> given.
  • Recognition: spelling resolved
  • Enforcement: 1/1 of the expected violations reported
psalm 6.18.0Psalm 6.18.0@536dd6236b39a5115385b0307b42d6d1ad431a02
next: 7.0.0-beta22
Unrecognized (pzoom≠)
phpdoc_advanced_phpstan_star_projection.php:78: Invalid type 'Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\*' in docblock for Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\printSize [InvalidDocblock]
phpdoc_advanced_phpstan_star_projection.php:86: Invalid type 'Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\*' in docblock for Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\writeStar [InvalidDocblock]
phpdoc_advanced_phpstan_star_projection.php:115: Argument 1 of Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\takesMixed expects Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<mixed>, but Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<int> provided [InvalidArgument]
pzoom (Psalm port)
phpdoc_advanced_phpstan_star_projection.php:80: Docblock class Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\* does not exist [UndefinedDocblockClass]
phpdoc_advanced_phpstan_star_projection.php:88: Docblock class Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\* does not exist [UndefinedDocblockClass]
phpdoc_advanced_phpstan_star_projection.php:90: Argument 1 of Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection::add expects Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\*, but 1 provided [InvalidArgument]
phpdoc_advanced_phpstan_star_projection.php:108: Argument 1 of printSize expects Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\*>, but Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<int> provided [InvalidArgument]
phpdoc_advanced_phpstan_star_projection.php:109: Argument 1 of printSize expects Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\*>, but Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<string> provided [InvalidArgument]
phpdoc_advanced_phpstan_star_projection.php:110: Argument 1 of writeStar expects Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\*>, but Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<int> provided [InvalidArgument]
phpdoc_advanced_phpstan_star_projection.php:115: Argument 1 of takesMixed expects Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<mixed>, but Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<int> provided [InvalidArgument]
  • Recognition: spelling not resolved — reported on declaration line(s) 78, 86
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved

Notes: Rejects `*` as InvalidDocblock and discards the whole `@param`, so Collection is untyped: the valid Collection<int>/Collection<string> calls stay silent and add() is not restricted. The contrast Collection<mixed> line still fires because that annotation does not use `*`.

mago 1.50.0mago 1.50.0 Enforced
phpdoc_advanced_phpstan_star_projection.php:90: Possible argument type mismatch for argument #1 of `Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection::add`: expected `never`, but possibly received `int(1)`. [possibly-invalid-argument]
phpdoc_advanced_phpstan_star_projection.php:115: Argument type mismatch for argument #1 of `Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\takesMixed`: expected `Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<mixed>`, but provided type `Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<int>` is less specific. [less-specific-nested-argument-type]
  • Recognition: spelling resolved
  • Enforcement: 1/1 of the expected violations reported
mir 0.78.0mir 0.78.0 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/1 of the expected violations reported
phpantom 0.10.0phpantom_lsp 0.10.0 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/1 of the expected violations reported
intelephense 1.18.5intelephense 1.18.5 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/1 of the expected violations reported
phpactor 2026.06.23.0Phpactor 2026.06.23.0 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/1 of the expected violations reported
phpy 1.0.19274phpy 1.0.19274 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/1 of the expected violations reported
qodana 262.9437.196Qodana 262.9437.196 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/1 of the expected violations reported

Notes: Silent on Collection<*>: no undefined-class complaint on `*`, and add() is not restricted to never.

noverify 0.5.5NoVerify, version 0.5.5: built on: 2025.04.22 14:36:46 OS: r-kuchinskas arm64 Commit: 4774b82f8adc53fbef38f95e97af4b953b4d1529 Unrecognized ⚠ 3 false positives
phpdoc_advanced_phpstan_star_projection.php:35: param $item miss matched with phpdoc type <<T>> [funcParamTypeMissMatch]
phpdoc_advanced_phpstan_star_projection.php:80: param $collection miss matched with phpdoc type <<Collection<*>>> [funcParamTypeMissMatch]
phpdoc_advanced_phpstan_star_projection.php:88: param $collection miss matched with phpdoc type <<Collection<*>>> [funcParamTypeMissMatch]
phpdoc_advanced_phpstan_star_projection.php:96: param $collection miss matched with phpdoc type <<Collection<int>>> [funcParamTypeMissMatch]
phpdoc_advanced_phpstan_star_projection.php:104: param $collection miss matched with phpdoc type <<Collection<mixed>>> [funcParamTypeMissMatch]
  • Recognition: spelling not resolved — reported on declaration line(s) 80, 88
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved
  • False positives: line(s) 35, 96, 104
Expectation diff
Line 35: Unexpected errors ["param $item miss matched with phpdoc type <<T>> [funcParamTypeMissMatch]"]
Line 96: Unexpected errors ["param $collection miss matched with phpdoc type <<Collection<int>>> [funcParamTypeMissMatch]"]
Line 104: Unexpected errors ["param $collection miss matched with phpdoc type <<Collection<mixed>>> [funcParamTypeMissMatch]"]
steins 0.1.8steins 0.1.8 (2026-09-21 revision 76306a9) Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/1 of the expected violations reported
phpstan-strict 2.2.15PHPStan - PHP Static Analysis Tool 2.2.15 Enforced
phpdoc_advanced_phpstan_star_projection.php:90: Parameter #1 $item of method Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<*>::add() expects never, int given.
phpdoc_advanced_phpstan_star_projection.php:115: Parameter #1 $collection of function Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\takesMixed expects Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<mixed>, Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<int> given.
  • Recognition: spelling resolved
  • Enforcement: 1/1 of the expected violations reported
psalm-next 7.0.0-beta22Psalm 7.0.0-beta22@de27e5724ee5997a1e3baee4d394ca6f4e46eba0 Unrecognized
phpdoc_advanced_phpstan_star_projection.php:78: Invalid type 'Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\*' in docblock for Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\printSize [InvalidDocblock]
phpdoc_advanced_phpstan_star_projection.php:86: Invalid type 'Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\*' in docblock for Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\writeStar [InvalidDocblock]
phpdoc_advanced_phpstan_star_projection.php:115: Argument 1 of Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\takesMixed expects Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<mixed>, but Conformance\Tests\PhpdocAdvancedPhpstanStarProjection\Collection<int> provided [InvalidArgument]
  • Recognition: spelling not resolved — reported on declaration line(s) 78, 86
  • Enforcement: 0/1 of the expected violations reported — incidental, since the spelling was not resolved

Notes: Same as Psalm 6: InvalidDocblock on `*`, the annotation is dropped, add() is unrestricted. Matches vimeo/psalm#11931.

Source

<?php

declare(strict_types=1);

namespace Conformance\Tests\PhpdocAdvancedPhpstanStarProjection;

/**
 * `Collection<*>` (star projection)
 *
 * A PHPStan call-site variance spelling. `*` as a type argument means the
 * function accepts a collection of *any* item type, and combines the write
 * restriction of covariance (`add()` expects `never`) with the read
 * restriction of contravariance (`get()` is `mixed`). It is not
 * `Collection<mixed>`: an invariant `Collection<mixed>` still rejects
 * `Collection<int>`.
 *
 * Mago implements it too. Psalm rejects `*` as `InvalidDocblock` and
 * discards the whole annotation (vimeo/psalm#11931).
 *
 * References:
 * - PHPStan phpdoc-types: Generics (`Collection<*>`)
 * - PHPStan "A guide to call-site generic variance" (star projections)
 * - https://github.com/vimeo/psalm/issues/11931
 */

/**
 * @template T
 */
final class Collection
{
    /**
     * @param T $item
     */
    public function __construct(
        public mixed $item,
    ) {
    }

    /**
     * @param T $item
     */
    public function add($item): void
    {
        $this->item = $item;
    }

    /**
     * @return T
     */
    public function get(): mixed
    {
        return $this->item;
    }

    public function count(): int
    {
        return 1;
    }
}

/**
 * @return Collection<int>
 */
function ints(): Collection
{
    return new Collection(0);
}

/**
 * @return Collection<string>
 */
function strings(): Collection
{
    return new Collection('x');
}

/**
 * @param Collection<*> $collection
 */
function printSize(Collection $collection): void // T: Collection<*>
{
    echo $collection->count(); // V: count() does not mention T
}

/**
 * @param Collection<*> $collection
 */
function writeStar(Collection $collection): void // T: Collection<*>
{
    $collection->add(1); // E?: add() on a star projection expects never
}

/**
 * @param Collection<int> $collection
 */
function writeInt(Collection $collection): void
{
    $collection->add(1); // V: the same write is valid on Collection<int>
}

/**
 * @param Collection<mixed> $collection
 */
function takesMixed(Collection $collection): void
{
}

printSize(ints()); // V
printSize(strings()); // V
writeStar(ints()); // V
writeInt(ints()); // V

// Contrast: invariant Collection<mixed> does not accept Collection<int>. A
// tool that read `*` as `mixed` rejects the V lines above the same way.
takesMixed(ints()); // E?[noise]: Collection<int> is not Collection<mixed>