42

Is there a type hint in PHP 8.3 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;
2

4 Answers 4

27

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

Edit Depending on how you interpret the question, @Pierre's answer could be considered more correct, since the OP said "type hint", although they showed a "type declaration".

There's a good thread from a while back arguing about the implications of what to call it, and that PHP's implementation is not a hint but a declaration. Some people argued that although calling it a "hint" is a misnomer, that shipped sailed and no matter what core changes, the community would still call it a hint. They did eventually update the documentation, however, to use "type declaration".

Personally, I find myself still saying "type hint" for the explicit type declaration, but I try to catch and correct myself. I do this because I'm trying to change my mindset so that if I talk to a non-PHP person (usually a JavaScript person), they know that I'm not talking about IDE hints but true language features.

Edit There’s a great post on the PHP Foundation's blog that shows the state of things as of August of 2024: State of Generics and Collections

Sign up to request clarification or add additional context in comments.

Comments

18

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;

3 Comments

That doesn't make the code itself type secure
The initial question was: Is there a type hint for an array of objects of a specific class in PHP 8.2?
Works with IntelliJ and other JetBrains products too
10

With new PHP features you can ensure that your array is always of type Task using variadic:

class MyClass
{
    /**
     * @var Task[] $tasks
     */
    private array $tasks = [];

    public function setTasks(Task ...$tasks) {
        $this->tasks = $tasks;
    }
}

$myClass = new MyClass();
$myClass->setTasks(...$tasksArray);
// or
$myClass->setTasks(new Task(), new Task(), new Task());

Since setTasks will always accept only Task as any parameter, there is no way to set anything else. We use this approach to bypass missing arrayof feature.

You can even incorporate magic methods to work with.

2 Comments

Nice one! Just want to mention that variadic functions were implemented using the ... operator in PHP 5.6. Then PHP 7 allowed you to declare types for variadic arguments.
Yes, it require parameter type hints. Also with union and intersection types it's very powerful
5

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.

2 Comments

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);
Wouldn’t !$value instanceof static instead of !$value instanceof Task make the code more generic?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.