Php 处理对象数组和intellisense

Php 处理对象数组和intellisense,php,phpstorm,Php,Phpstorm,我发现很多时候我会将自定义对象数组传递给函数进行处理。在我的函数中,在访问内部属性/方法之前,我检查以确保它是正确的类 因为我使用的是数组,而且据我所知PHP没有任何类型化的泛型列表,所以我不能使用类型暗示,所以IDE中的intellisense无法工作,代码检查会抛出警告 我遇到一篇老文章,其中提出了在开发过程中加入这行代码以使intellisense正常工作的想法: if (false) $myObj = new MyObject(); 因此,我最终得到了一个如下所示的函数: functi

我发现很多时候我会将自定义对象数组传递给函数进行处理。在我的函数中,在访问内部属性/方法之前,我检查以确保它是正确的类

因为我使用的是数组,而且据我所知PHP没有任何类型化的泛型列表,所以我不能使用类型暗示,所以IDE中的intellisense无法工作,代码检查会抛出警告

我遇到一篇老文章,其中提出了在开发过程中加入这行代码以使intellisense正常工作的想法:

if (false) $myObj = new MyObject();
因此,我最终得到了一个如下所示的函数:

function ProcessObjectArray(array $arrayOfObject)
{
    foreach ($arrayOfObject as $key => $myObj) {
        if (get_class($myObj) == 'MyNamespace\MyObject') {
            if (false) $myObj = new MyObject();
            // I can now access intellisense for MyObject in here

        } else {
            trigger_error('is not right object');
        }
    }
}
这看起来有点奇怪,所以我想知道这是否是我没有以最佳方式处理对象数组的迹象,或者是否有更好的方式让我的intellisense工作。我查看了arrayobject接口,看看是否可以创建一个实现arrayobject的类,该类将保存一个类型化列表。虽然将所有验证放在其构造函数或类似追加的函数中很好,但我无法让它与intellisense一起工作,因为内部容器仍然只是一个标准数组。另外,使用
get\u class
似乎并不好,因为如果重命名了类名或命名空间,那么IDE重构功能就不会选择此引用(好吧,PHPStorm至少不会,我正在使用它)


我当然不需要intellisense,但这种奇怪的黑客行为让我怀疑我是否有正确的PHP OOP方法,并认为我可能遗漏了一些东西。这是正确的方法还是我遗漏了什么?

如果你这样做,我会避免使用are本机数组。我将创建包含某种类型数组的类。这样,您可以在类的构造函数中验证数组内容,然后可以使用PHP允许的对象的实际类型提示。

使用phpstorm添加注释时,它将正确地为您完成代码

/**
 * @param MyNamespace\MyObject[] $arrayOfObject
 */
function ProcessObjectArray(array $arrayOfObject)
{
    foreach ($arrayOfObject as $key => $myObj) {
        if (get_class($myObj) == 'MyNamespace\MyObject') {
            if (false) $myObj = new MyObject();
            // I can now access intellisense for MyObject in here

        } else {
            trigger_error('is not right object');
        }
    }
}
然而,intellisense不会阻止您传入不正确的对象,它只会在编码时帮助您防止传入不正确的对象

也许您希望考虑使用集合而不是使用通用数组。

有很多例子,但是这里有一个简单的例子,你可以在上面展开

class Collection 
{
    /** @var array */
    private $items = [];

    /**
     * @param MyNamespace\MyObject $obj
     * @return $this
     */
    public function addItem(MyNamespace\MyObject $obj) {
        $this->items[] = $obj;
        return $this;
    }

    /**
     * @param $index
     * @return $this
     */
    public function deleteItem($index) {
        unset($this->items[$index]);
        return $this;
    }

    /**
     * @param $index
     * @return MyNamespace\MyObject|null
     */
    public function getItem($index) {
        return array_key_exists($index, $this->items) ? $this->items[$index] : null;
    }

    /**
     * @return MyNamespace\MyObject[]
     */
    public function getItems() {
        return $this->items;
    }

    /**
     * @return int
     */
    public function count() {
        return sizeOf($this->items);
    }
}
下面是一个例子,说明了所有这些是如何工作的:

$collection = new \Collection;

$obj = new MyNamespace\MyObject;

$collection->addItem($obj);

foreach($collection->getItems() as $item) {
    // this will already know that $item is MyNamespace\MyObject because of the annotation on the getItems() method
    $item->doSomething();
}
这样,除了
CollectionElement
之外,您不能向集合中添加任何内容。及之后:

foreach($collection as $element){
    /** @var CollectionElement $element */
    $element->//here you will have autocompletion
}

你不需要检查任何东西,因为你的集合永远不会包含你不期望的东西。

“一般来说,PHP对于任何严肃的类型工作来说都是一种糟糕的语言。”我畏缩。“我畏缩”。只是出于好奇,为什么?我认为PHP是广泛使用的最弱/松散类型,这一点没有争议。我只是尝试了一下,但自动完成不起作用。知道我错过了什么吗?我知道了,没有在current()上指定返回类型。谢谢,使用这样的模式我感觉好多了。当我在另一个函数中迭代它的成员时,如何对这个集合进行注释,使自动补全工作?getItems()上的注释应该可以很好地涵盖这种情况。我将此与其他答案结合起来,得到了完美的结果。谢谢你的帮助!嗯,在您的示例中,您使用getitems()初始化一个数组,然后在该数组上迭代,或者使用for循环和getItem()而不是foreach?
foreach($collection as $element){
    /** @var CollectionElement $element */
    $element->//here you will have autocompletion
}