/**
 * @template T of \Exception
 * @param T $a
 * @return T
 */

/**
 * @template T
 * @param class-string<T> $className
 * @param int $id
 * @return T|null
 */
function findEntity(string $className, int $id)
{
    // ...
}

ジェネリックなinterfaceの実装およびジェネリックなクラスの継承をするには、二つの選択肢があります。

親のジェネリック性を維持し、子クラスも同様にジェネリックにする
インターフェイス/親クラスの型変数を指定する (子クラスはジェネリックではない)
ジェネリック性を維持するには子クラスの上に同じ @template を繰り返し、@extendsタグまたは@implementsタグに渡します。

<?php

/**
 * @template T
 * @implements Collection<T>
 */
class TestCollection implements Collection
{
}

クラスをジェネリックにしたくない場合は @extends または @implements だけを書きます。

<?php

/**
 * @implements Collection<Pizza>
 */
class PizzaCollection implements Collection
{
}

関連記事