【问题标题】:Function return type hinting for an array of objects in PHP7PHP7中对象数组的函数返回类型提示
【发布时间】:2017-04-03 06:31:40
【问题描述】:

我对 PHP 7 中的新功能非常满意。但我对如何在 PHP 7 中返回对象数组感到困惑。

例如,我们有一个类Item,我们想从我们的函数中返回一个该类的对象数组:

function getItems() : Item[] {
}

但是这样不行。

【问题讨论】:

    标签: php php-7


    【解决方案1】:

    我实际上明白你的意思,但不幸的是,答案是你不能那样做。 PHP7 缺乏这种表达能力,因此您可以声明您的函数以返回“数组”(一个通用数组),或者您必须创建一个新的 ItemArray 类,它是一个 Item 数组(但这意味着您必须自己编写代码)。

    目前没有办法表达“我想要一个 Item 数组”实例。

    编辑:作为补充参考,这里是您想做的"array of" RFC,由于各种原因,它已被拒绝。

    【讨论】:

    • 我认为迁移到 PHP 7 可以帮助我创建严格类型的代码:/
    • 我知道,这令人失望 :( 我添加了对 RFC 的引用,该引用准确地谈到了您询问的功能。它被拒绝了。
    • @Johnny ,我不懂 PHP 的 rfc 投票方法,他们为什么不看一眼就拒绝东西,这没有任何理由,直接投票不是一个好的系统
    • 目前我们只能使用实现 ArrayAccess 和 Iterator 接口的自定义类以及一些自定义输入验证。 RFC也来自2014年,应该重新审视。这将是类型化数组的又一步。就像在 Java 中的 String[], int[].
    • 那个 RFC 也很老了,是为 php5.6 提出的。我认为他们应该重新考虑它,现在我们都在朝着严格的打字方向前进,它比最初提出时更有意义。
    【解决方案2】:

    您可以使用docblocks 以这种方式输入提示。

    PhpStorm 这样的 PHP 编辑器 (IDE) 非常支持这一点,并且在迭代此类数组时会正确解析该类。

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

    PHPStorm 也支持嵌套数组:

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

    较新版本的 PHPStorm 支持 phpstan/psalm 格式:

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

    【讨论】:

    • 是的,phpactor也支持
    • 也适用于 NetBeans。
    • 仅供参考,这不适用于 VSCode + Intelliphense 扩展
    • 我不会使用除了 PhpStorm 以外的任何东西。
    • 虽然我赞成你“使用 phpdocs”,但这不是关于>Generics
    【解决方案3】:

    当前版本的 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)
        }
      }
    }
    

    【讨论】:

    • 这是一个很好的方法,但我更喜欢自动的方式,我希望他们在不久的将来实现这个功能,谢谢:)
    • 谢谢。我注意到一件事。是否应该是私有的 $container = [];而不是私人 $items = []; ?
    • @kta,你是对的。我已经编辑了答案。谢谢。
    【解决方案4】:

    目前不可能。但是您可以使用自定义数组类来实现您的预​​期行为

    
    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');
        }
    }
    

    感谢bishop's answer here

    【讨论】:

      【解决方案5】:

      我相信这就是你要找的东西

      <?php
      class C {}
      
      function objects()
      {
          return array (new C, new C, new C);
      }
      list ($obj1, $obj2, $obj3) = objects();
      
      var_dump($obj1);
      var_dump($obj2);
      var_dump($obj3);
      ?>
      

      【讨论】:

        猜你喜欢
        • 2021-12-15
        • 1970-01-01
        • 2021-02-17
        • 2014-03-06
        • 1970-01-01
        • 2020-04-04
        • 2017-09-09
        • 2010-10-21
        相关资源
        最近更新 更多