处理对象和智能感知的数组

时间:2015-04-21 18:06:46

标签: php phpstorm

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

因为我正在使用数组,据我所知,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_class似乎并不好像重命名类名称或命名空间,然后IDE重构功能不会选择此引用(好吧,PHPStorm至少不是,我正在使用它)。

我当然不需要intellisense,但是这个黑客的怪异让我想知道我是否有正确的方法来处理PHP中的OOP,并认为我可能会遗漏一些东西。这是正确的做法还是我错过了什么?

3 个答案:

答案 0 :(得分:3)

使用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();
}

答案 1 :(得分:2)

class MyCollection implements \Iterator
{
    /**
     * @var CollectionElement[]
     */
    private $elements = [];


    public function addElement(CollectionElement $element)
    {
        $this->elements[] = $element;
    }

    /**
     * @return CollectionElement
     */
    public function current()
    {
        return current($this->elements);
    }

    //... Rest of the Iterator implementation
}

这样您就无法将除CollectionElement以外的任何内容添加到集合中。之后:

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

您不需要检查任何内容,因为您的收藏品永远不会包含任何您不期望的内容。

答案 2 :(得分:-5)

如果你要走这条路线,我会避免使用原生阵列。我会创建包含某种类型的数组的类。这样,您可以在类的构造函数中验证数组内容,然后您可以使用PHP允许的对象的实际类型提示。