21

Is there a type hint in PHP 8.2 which allows using ExampleClass[] for declaring it is an array of objects of the class ExampleClass?


In my specific case, ExampleClass is called Task

What I want but does not work:

private Task[] $tasks;

My PHPStorm IDE tells me that Plural types are allowed only in doc types
- speaking that only in PHPDoc using Tasks[] would be totally fine. But I want to use plain PHP.

The error is: PHP Parse error: syntax error, unexpected token "[", expecting variable


If I would only need one object Task and not an array of objects Task[] it would work with:

private Task $task;

This is my current, working workaround:

private array $tasks;
WebDevPassion
  • 422
  • 1
  • 4
  • 12
  • 1
    See also: https://stackoverflow.com/q/20763744/157957 https://stackoverflow.com/q/778564/157957 – IMSoP Mar 10 '22 at 19:34

3 Answers3

16

The short answer is no.

My understanding is that enforcing such a thing has terrible performance problems. Some people want to go all the way and have full blown generics, others just want type-safe collections. Some people worry that implementing the latter first might hinder the development of the former in the future. So we’re at a standstill.

There’s the occasional discussion in the community such as this: https://externals.io/message/108175

Chris Haas
  • 53,986
  • 12
  • 141
  • 274
4

While there is not a type hint available for such compound types, there is a workaround that enforces type. Create a subclass from ArrayObject and validate all values added to the ArrayObject. Then you can type hint your new subclass.

<?php

class Collection extends ArrayObject
{
    public function __construct(array $items = [])
    {
        foreach ($items as $item) {
            $this->validate($item)
        }
    }

    public function append($value): void
    {
        $this->validate($value);
        parent::append($value);
    }

    public function offsetSet($key, $value): void
    {
        $this->validate($value);
        parent::offsetSet($key, $value);
    }

    protected function validate($value): void
    {
        if (!$value instanceof Task) {
            throw new InvalidArgumentException(
                'Not an instance of Task'
            );
        }
    }
}

Now you can return objects with a type hint of Collection and it will behave exactly as an array of Task objects.

  • Welcome to SO and thanks for the contribution. – WebDevPassion Sep 16 '22 at 05:46
  • For those who are trying to implement this approach, please keep in mind that the constructor misses the parent constructor call after the loop - ```parent::__construct($items);``` – Zippp Apr 06 '23 at 13:58
  • Wouldn’t `!$value instanceof static` instead of `!$value instanceof Task` make the code more generic? – psychoslave Apr 17 '23 at 21:29
2

If you're using PhpStorm, PHPStan or Psalm, types can be defined in PHPDocs and these tools will do the type checking, among many other things.

/** @var Task[] $tasks */
private array $tasks;
Clonkex
  • 3,373
  • 7
  • 38
  • 55
Pierre
  • 1,044
  • 15
  • 27