在foreach循环中将变量转换为对象类型的PHP强制转换

45

在以下代码中,$quiz_object->personalities 包含一个 Personality 对象数组。

// Loop through each personality that exists for the quiz
foreach($quiz_object->personalities AS $existing_personality)
{

    // Show all of the existing personalities
    echo $existing_personality->GetQuizMakerPersonalityHTML();
}

在foreach循环中,如何将我的变量$existing_personality“转换”(我认为这是正确的词)为对象类型?

我希望这样做是为了当我键入$existing_personality->时,可以获取该对象类型可用的公共函数列表。

更新

目前,Zend Studio不知道我正在循环遍历一个Personality对象数组,它只认为这是一个标准变量。但实际上它是一个类型,我的代码完全正常运行。我只是希望在foreach循环内部的变量上获得IDE提示。

只是为了明确,如果我有:

$personality_object = new Personality();

// I get the IDE hints here
echo $personality_object->MyFunction();

但是,一旦我开始使用 foreach 循环遍历数组对象,Zend 就不知道我正在遍历对象数组。

以下是在我的 Personality 对象内最初定义人物数组的方式:

class Personality
{

    // Array of Personality objects
    public $personalities = array();

}

2
你是在说启用IDE提示吗? - deceze
1
我可以获取其他对象的提示,但是不能获取在foreach循环中的对象的提示。 - Luke
你运行代码时是否出现了任何错误,还是只是你的IDE有些问题? - Jørgen R
6个回答

109

这很大程度上取决于您使用的集成开发环境(IDE)。

在Netbeans和IntelliJ中,您可以在注释中使用@var

/* @var $variable ClassName */
$variable->

现在IDE将知道$variable是ClassName类的实例,并在->后面提示。

您也可以在自己的IDE中尝试它。

您还可以在getPersonalities()方法中创建一个@return注释,声明返回值将是ClassName[],这意味着是ClassName对象的数组:

/**
 * Returns a list of Personality objects
 * @return Personality[]
 */
function getPersonalities() {
    return $this->personalities;
}
这还取决于你的集成开发环境如何解释这种提示。要在foreach循环中使用它,可以采用以下方法1:
/* @var $existing_personality Personality */
foreach( $quiz_object->personalities as $existing_personality ){
}

或2:

foreach( $quiz_object->getPersonalities() as $existing_personality ){
}

如果你的集成开发环境够友好,两种方法都应该启用IDE提示。

另外需要注意的是,如果你想在自己的类中使用它,可以在声明类变量时使用相同的签名:

class MyClass
{ 

    /** 
    * @var ClassName[] $variable List of ClassName objects. 
    */ 
    var $variable;

}

1
转换是否与IDE无关? - Xanlantos
1
如果可能的话会很好,但由于PHP不是强类型语言,这只是对特定IDE的建议。然后就取决于IDE如何解释提示了。 - Krycke
有人知道如何在Visual Studio Code中获得相同的效果吗?上面的解决方案适用于NetBeans PHP,但我希望能够找到VS Code的解决方案。 - Dawid Ohia
太棒了,非常感谢!你的 /** @var... 提示救了我一命,因为它在 PhpStorm 中也能正常工作 :) - Richard Kiefer
/* @var $variable ClassName */ 这个语法在 Eclipse 中也能正常工作。 - Big Guy
我读成“在foreach循环中使用你可以做到一件事!”然后我就想...好吧...那就算了吧... - LukasKroess

14

我觉得这对于那些使用phpStorm的人可能有所帮助。

我发现让IDE自动填充对象的方法是通过在操作之前包含快速if检查来检查对象是否存在以及$var是否为该对象的实例。

例如:

foreach ($objArray as $obj) {
    if (is_object($obj) && $obj instanceof DataObject) {
        $obj->thisMethodShouldBeAvailableInPHPStormNow();
    }
}

在寻找更好的方法时发现了这个问题,但是上述方法对我有效。

干杯!


太好了,还有另一种方法/** @var $variableName ClassName */在PhpStorm中也可行。当然,它并不会进行任何真正的类型检查 :) - Richard Kiefer

7
我知道这篇文章很旧,但我认为它可能会有所帮助:
在PhpStorm中,是这样的,其他编辑器也可能如此。
/**
 * @param ClassName[] $variables
 */
public function loopFunction($variables){
    foreach ($variables as $variable) {
        echo $variable->functionName();
    }
}

1
太棒了!如果你有一个成员变量,你也可以用 /** @var ClassName[] */ 的方式记录它,并且在类内的所有地方都会有类型提示。如果你通过某个 getter 方法使这个成员变量可用,即使你的 getter 函数的返回值没有明确记录,使用者也会得到类型提示。 - Richard Kiefer

3

您可以在foreach内部随时调用一个单独的函数,并在函数声明中声明类。这可能也有让您在其他地方重复使用此代码的好处。例如,在下面的getPriceFromProduct函数中,您可以看到我如何将$product的类声明为Product。

当然,我同意不必以这种方式进行操作会更好,但是它确实有效。

class ProductBundle {

  private $products; //buy this
  public function get_products() { return $this->products; }
  public function add_product($product) { $this->products[] = $product; }

  public function get_price() {
        $products = $this->get_products();
        $prices = array();
        foreach($products as $product) {
            $prices[] = $this->getPriceFromProduct($product);
        }
        return array_sum($prices);
    }

    private function getPriceFromProduct(Product $product) {
        $price = $product->get_price();
        return $price;
    }

2

对于 VS Code,情况正好相反(先是类名)

/**@var ClassName $variable*/
foreach ($objArray as $variable) 
{...}

1

如果你想在代码中使用实际的类型声明,而不是注释,因为这可能会因IDE而异,你可以使用array_*函数,例如array_walk

array_walk($quiz_object->personalities, function (Personality $p) {
    echo $existing_personality->GetQuizMakerPersonalityHTML();
});

阅读了这个建议后,我面对同样的挑战,开始使用array_walk进行工作。我发现这种技术需要将本地变量作为参数传递给函数,因为它们在包含array_walk的函数中是in-scope的,但不在闭包函数的in_scope中。一旦你意识到你需要超过几个变量,这就开始显得不太优雅了。此时,我认为应该考虑其他建议之一,甚至只需重新分配元素变量以进行UI转换,例如: $casted = (class)$element; - TonyG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接