Function return type hinting for an array of objects in PHP7

Solution 1:

You can type hint this way using docblocks.

PHP editor (IDE) like PhpStorm supports this very well and will properly resolve the class when iterating over such array.

/**
 * @return YourClass[]
 */
public function getObjects(): iterable

PHPStorm also supports nested arrays:

/**
 * @return YourClass[][]
 */
public function getObjects(): iterable

Newer versions of PHPStorm support phpstan/psalm format:

/**
 * @return array<int, YourObject>
 */
public function getObjects(): array

Solution 2:

I actually understand what you mean, but the answer unfortunately is that you can't do that. PHP7 lacks that kind of expressivity, so you can either declare your function to return "array" (a generic array) or you have to create a new class ItemArray which is an array of Item (but that meaning you will have to code it yourself).

There is currently no way to express "I want an array of Item" instances.

EDIT: As an added reference, here the "array of" RFC of what you wanted to do, it has been declined due to various reasons.

Solution 3:

The current version of PHP doesn't support a built-in type hinting for an array of objects, as there is no such data type as "an array of objects". A class name can be interpreted as a type in certain contexts, as well as array, but not both at a time.

Actually you can implement such kind of strict type hinting by creating a class based on the ArrayAccess interface, e.g.:

class Item
{
    protected $value;

    public function __construct($value)
    {
        $this->value = $value;
    }
}

class ItemsArray implements ArrayAccess
{
    private $container = [];

    public function offsetSet($offset, $value)
    {
        if (!$value instanceof Item) {
            throw new Exception('value must be an instance of Item');
        }

        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    public function offsetExists($offset)
    {
        return isset($this->container[$offset]);
    }

    public function offsetUnset($offset)
    {
        unset($this->container[$offset]);
    }

    public function offsetGet($offset)
    {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }
}


function getItems() : ItemsArray
{
    $items = new ItemsArray();
    $items[0] = new Item(0);
    $items[1] = new Item(2);
    return $items;
}

var_dump((array)getItems());

Output

array(2) {
  ["ItemsArrayitems"]=>
  array(0) {
  }
  ["container"]=>
  array(2) {
    [0]=>
    object(Item)#2 (1) {
      ["value":protected]=>
      int(0)
    }
    [1]=>
    object(Item)#3 (1) {
      ["value":protected]=>
      int(2)
    }
  }
}