Generics in PHP: A Complete Guide to Typing with Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why Generics Are Not Just a Trend, but a Necessity?

\n\n

If you've ever written PHP code that worked with collections, repositories, or a service layer, you've likely encountered a situation: a function accepts array, but what's inside is a mystery. Maybe it's users, or maybe it's cats. Or, even worse — both. This is exactly where Generics come to the rescue — a powerful typing tool that makes your code predictable, safe, and self-documenting.

\n\n

In this article, we'll break down how generics work in PHP, why they are needed, and how to use them in real projects. You'll learn how to avoid common mistakes and make your code professional. Let's go!

\n\n

What Are Generics in Simple Terms?

\n\n

Imagine you are an online store developer. You have a Cart class that stores items. Without generics, you write:

\n\n
class Cart {\n    private array $items;\n    \n    public function addItem($item): void {\n        $this->items[] = $item;\n    }\n    \n    public function getItems(): array {\n        return $this->items;\n    }\n}
\n\n

The problem? $item can be anything — a number, a string, a Product object, or even null. The IDE won't tell you what type is returned from getItems(). You'll have to dig into the documentation or debug.

\n\n

Generics solve this problem. They allow you to specify: "Hey, this class only works with products!". It looks like this:

\n\n
class Cart {\n    /** @param Product[] $items */\n    private array $items;\n    \n    public function addItem(Product $item): void {\n        $this->items[] = $item;\n    }\n    \n    /** @return Product[] */\n    public function getItems(): array {\n        return $this->items;\n    }\n}
\n\n

But this is just an imitation. Real generics in PHP appeared with PHP 8.0, and full support came in PHP 8.1+ using attributes and static analysis (e.g., PHPStan or Psalm).

\n\n

How Do Generics Actually Work in PHP?

\n\n

Unlike Java or C#, PHP does not have native syntax-level support for generics (yet). However, thanks to PHPDoc annotations and static analysis tools, we can get all the benefits of typing.

\n\n

Template Types

\n\n

The most popular approach is to use @template in PHPDoc. Let's look at an example with a collection:

\n\n
/**\n * @template T\n */\nclass Collection {\n    /** @var array<int, T> */\n    private array $items = [];\n    \n    /**\n     * @param T $item\n     */\n    public function add(mixed $item): void {\n        $this->items[] = $item;\n    }\n    \n    /**\n     * @return T\n     */\n    public function get(int $index): mixed {\n        return $this->items[$index] ?? throw new \\OutOfBoundsException();\n    }\n}
\n\n

Now, when using this class, you specify the concrete type:

\n\n
/** @var Collection<User> $userCollection */\n$userCollection = new Collection();\n$userCollection->add(new User('Alice'));\n$user = $userCollection->get(0); // PHPStan knows: $user is a User\necho $user->name; // Safe!
\n\n

Constraints for Generics

\n\n

Sometimes you need the type T to not be just anything, but to implement a specific interface. This is called a bound:

\n\n
/**\n * @template T of \\JsonSerializable\n */\nclass JsonCollection {\n    /** @var array<int, T> */\n    private array $items = [];\n    \n    public function toJson(): string {\n        return json_encode($this->items);\n    }\n}
\n\n

Now you won't be able to add an object to the collection that does not implement JsonSerializable. The IDE and static analyzer will throw an error.

\n\n

Practical Examples: From Simple to Complex<

Blogs

Book Recommendations