PHP Casting Variable as Object type in foreach Loop
Asked Answered
D

6

46

Within the following code, $quiz_object->personalities contains an array of Personality objects.

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

How do I "cast" (I think that's the right word) my variable $existing_personality within the foreach loop as the object type?

I wish to do this so that when I type $existing_personality->, I get the list of public functions available for that object type.

UPDATE

At the moment, Zend Studio doesn't know I am looping through an array of Personality objects within the loop, it just thinks it's a standard variable. However, it is a type and my code works perfectly well. I just want the IDE hints on my variable within the foreach loop.

Just so that I'm clear, the hints appear for every other object, if I have:

$personality_object = new Personality();

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

But as soon as I start looping in a foreach, Zend has no way of knowing that I'm looping through an array of Objects.

This is how the array of personalities is defined initially within my Personality object:

class Personality
{

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

}
Detailed answered 13/9, 2012 at 15:36 Comment(3)
Are you just talking about enabling IDE hints?Merthiolate
I get the hints for every other object, but not for ones that I have in foreach loops.Detailed
Yeah, but do you get any errors when you run the code, or is it just your IDE that's being lame?Whitebeam
F
111

It much depends on the IDE you are using.

In Netbeans and IntelliJ you are able to use @var in a comment:

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

The IDE will now know that $variable is of the class ClassName and hint after the ->.

You can try it out in your own IDE as well.

You can also create a @return annotation in a getPersonalities() method stating that the return will be a ClassName[], which means an array of ClassName objects:

/**
 * Returns a list of Personality objects
 * @return Personality[]
 */
function getPersonalities() {
    return $this->personalities;
}

this also depends on how your IDE is interpreting this type of hinting.

To use this in foreach loops you can do 1:

/* @var $existing_personality Personality */
foreach( $quiz_object->personalities as $existing_personality ){
}

or 2:

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

both should enable IDE hinting, if your IDE is kind enough.

As an extra note, if you want to use this inside it's own class, you can use the same signature when declaring a class variable:

class MyClass
{ 

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

}
Falk answered 13/9, 2012 at 16:10 Comment(6)
Would casting be IDE independent?Skip
Would be nice if it was, but as php is not strongly typed, this is just a suggestion to the specific IDE. And then it's up to the IDE how they want to interpret the hinting.Falk
Does anyone know how to get the same effect in Visual Studio Code? Above solution works for NetBeans PHP, but I would appreciate the solution for VS Code.Tubercular
Awesome, thank you so much! Your /** @var... hint has rescued me, because it is also working in PhpStorm :)Agnosia
The /* @var $variable ClassName */ also works in EclipseTrictrac
I read it as 'to use this in foreach loops you can do one!' and was like... okay then... guess that's a no...Eggers
A
14

just thought I'd throw this in there for those using phpStorm.

I found the way to get the IDE to auto-populate the methods for an object was by including a quick if check beforeheand checking that the object exists and that the $var was an instance of said object.

Example:

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

Found this question while searching for a better way, but the above works for me.

Cheers!

Acquiescent answered 5/2, 2014 at 1:21 Comment(1)
Great to know! Also, the approach of /** @var $variableName ClassName */ from another answer works in PhpStorm. Although, it does not do any real type checking, of course :)Agnosia
A
7

I know this post is old but I think this may help someone:

In PhpStorm works this way, maybe in others too.

/**
 * @param ClassName[] $variables
 */
public function loopFunction($variables){
    foreach ($variables as $variable) {
        echo $variable->functionName();
    }
}
Anastomosis answered 13/5, 2016 at 7:56 Comment(1)
Amazing! If you have a member variable, you can also document it your way with /** @var ClassName[] */and it is type hinted in all places within your class. And if you make this member available via some getter, the consumer will also get the type-hint even if your getter function's return value was not documented explicitly.Agnosia
B
3

You can always call out to a separate function from within the foreach, and declare the class in the function declaration. This might also have the benefit of letting you reuse this code elsewhere. For example inside the function getPriceFromProduct below, you see how I declare the class of $product to be Product.

Of course I agree it would be nice to not have to do it this way but hey, it works.

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;
    }
Bobbie answered 16/10, 2014 at 22:55 Comment(0)
A
2

for VS Code it's the other way around (ClassName first)

/**@var ClassName $variable*/
foreach ($objArray as $variable) 
{...}
Acanthocephalan answered 5/8, 2022 at 17:47 Comment(0)
B
1

If you want actual type declarations in the code as opposed to comments that could be picked up differently depending on the IDE, you can use the array_* functions, for example array_walk.

array_walk($quiz_object->personalities, function (Personality $p) {
    echo $existing_personality->GetQuizMakerPersonalityHTML();
});
Biretta answered 19/3, 2018 at 16:51 Comment(1)
After reading this suggestion, and with the same challenge, I started to work with the array_walk. I found that this technique requires passing in local variables to the function as arguments, as they are in-scope for the function containing the array_walk, but not in_scope of the closure function. As soon as you realize that you need more than a couple variables, this starts to look inelegant. At that point I think one of the other suggestions should be considered, maybe even just reasigning the element var to a new one with casting for the UI, as in: $casted = (class)$element;Lichter

© 2022 - 2024 — McMap. All rights reserved.