我对PHP 7的新特性感到非常高兴。但是我对如何在PHP 7中返回对象数组感到困惑。
例如,我们有一个类Item
,我们想从函数中返回该类的对象数组:
function getItems() : Item[] {
}
但事实并非如此。
/**
* @return YourClass[]
*/
public function getObjects(): array
PHPStorm 同时支持嵌套数组:
/**
* @return YourClass[][]
*/
public function getObjects(): array
PHPStorm 的新版本支持 phpstan/psalm 格式:
/**
* @return array<int, YourObject>
*/
public function getObjects(): array
甚至可以使用泛型:
/**
* @template T of object
* @param class-string<T> $className
* @return array<array-key, T>
*/
public function getCollectionOf(string $className): array
我实际上理解你的意思,但不幸的是,你不能这样做。PHP7缺乏这种表达能力,所以你可以声明函数返回“array”(一般数组),或者你必须创建一个新类ItemArray,它是一个Item数组(但这意味着你需要自己编写代码)。
目前没有办法表达“我想要一个Item数组”实例。
编辑:作为一个额外的参考,这里是你想要做的"array of" RFC的链接,由于各种原因已经被拒绝。
当前版本的PHP不支持对“对象数组”进行内置类型提示,因为没有“对象数组”这样的数据类型。在某些情况下,类名可以被解释为类型,以及array
,但不能同时使用。
实际上,你可以通过创建一个基于ArrayAccess
接口的类来实现这种严格的类型提示,例如:
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());
输出
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)
}
}
}
目前还不可能。但是您可以通过自定义数组类来实现所需的行为。
function getItems() : ItemArray {
$items = new ItemArray();
$items[] = new Item();
return $items;
}
class ItemArray extends \ArrayObject {
public function offsetSet($key, $val) {
if ($val instanceof Item) {
return parent::offsetSet($key, $val);
}
throw new \InvalidArgumentException('Value must be an Item');
}
}