19

I have an object with lots of properties. Some of the properties have their names start with the same string of text (in my example to come "bullet"), followed by an integer.

I can fetch the property values as follows:

echo $objectName->bullet1;
echo $objectName->bullet2;
echo $objectName->bullet3;

and so on.

I'm trying to write a for loop to get the first 20 of these, and at the moment it looks a bit like:

for ($i = 1; $i <= 20; $i++){
 if ($objectName->bullet$i){
  echo $objectName->bullet$i;
 }
}

But this isn't working. I know I could write something like

$bulletsArray[1] = $objectName->bullet1;
$bulletsArray[2] = $objectName->bullet2;
$bulletsArray[3] = $objectName->bullet3;

all the way through to 20, then put a for loop on that, but I'm sure there must be a cleaner way. Can someone point me in the right direction?

5
  • 1
    Additional information: The actual object isn't my creation - it comes from using SimpleXMLElement on an external XML file created by a third-party. Commented Nov 18, 2012 at 13:20
  • It is generally a bad idea to enumerate properties like that. What exactly are these properties? If they're just a collection of identical/similar entities, there are better approaches than this. Please provide more information about the problem you want to solve. Commented Nov 18, 2012 at 13:32
  • 1
    Markus, the "bullet" properties are strings of text containing miscellaneous information about an item. They come from using SimpleXMLEement to process an XML file that has code like: <bullet1>Something</bullet1> <bullet2>Something else</bullet2> <bullet3>Another thing</bullet3> Commented Nov 18, 2012 at 13:41
  • Regardless of the fact that this is bad XML, you should not be mapping those fields to class properties but rather use Iterators or directly with parts of the SimpleXML Object. Commented Nov 18, 2012 at 13:49
  • From your information I take the exact number of such bullet fields varies from case to case which is a clear sign that you should have a collection of them and iterate through that collection. A collection can be an array of strings or an array of SimpleXML objects or your own bullet objects. A class should not have a variable number of properties and properties should not be enumerated collections. Commented Nov 18, 2012 at 13:52

4 Answers 4

20

This is how you can do it:

for ($i = 1; $i <= 20; $i++){
    $propertyName = "bullet$i";
    if ($objectName->$propertyName){
        echo $info->$propertyName;
    }
}

Though I think using an array instead of the object would be a better solution.

Sign up to request clarification or add additional context in comments.

4 Comments

Important caveat: this will throw E_STRICT warnings.
@user1800246: agreed. An alternative is to either use reflection (just as ugly but doesn't throw warnings) or get rid of the object altogether and use an array instead.
I'll have to disagree on the ugliness of it. What you are doing is essentially trying variables at random - this works fine for 20 variables...but imagine 500? 1000? Reflection doesn't have this issue, as it does not try - it goes straight to the object.
@user1800246: I meant that the problem the asker is trying to solve with this probably has a much more elegant solution than looking up an object's properties. I didn't mean it as variable variables vs reflection - I totally agree that reflection is the better way.
8
$var = 'myVariable';
$value = $object->$var;

is the correct syntax for accessing a field by name in PHP.

In your case it would look something like this:

for ($i = 1; $i <= 20; $i++) 
{
     $var = 'bullet'.$i;

     if ($objectName->$var)
     {
          echo $info->$var;
     }
}

Comments

7

Both previous answers have the "try it, if it doesn't work, move on" and are working for a very specific situation. Let me give you a more generic approach, which, sadly, requires PHP 5.

A bit about Reflection

Reflection allows you to reflect on an object or class to extract useful information about it. In particular, you can use Reflection to get all the properties set in a class, whether static, at run-time, or generated on the go.

To do this, start by initiating your Reflection object (assuming your class object is $object) as follows:

$refObj = new ReflectionObject($object);

This will now give you a reflection interface. Notice the useful ReflectionObject::getProperties() method - it allows you to get all properties set in a class (and you can filter by public, protected, private etc... if needed). We'll use exactly this:

$yourNewArray = array();
$PropertyArray = $refObj->getProperties();
$pCount = count($PropertyArray);
for ($i = 0; $i < $pCount; $i++) {
   $yourNewArray[$PropertyArray[$i]->getName()] = $PropertyArray[$i]->getValue($object);
}

Done. Completely generic, works anywhere.

4 Comments

As nice as this may seem, it IMO is not good advice. If the OP has very special requirements, the use of reflection may be contemplated but I assume the OP is trying to solve a common problem with the wrong approach and using reflection for common problems is not a good idea. Reflection is a meta-tool and should rather not be used in productive code. It breaks all sorts of bounderies and OOP best practices.
From a pure efficiency point of view, despite reflection being a meta-tool, using it to iterate over object properties is cleaner and quicker than a loop over unknown names. Don't believe me? Benchmark it for 1k-10k variables. Also... "OOP best practices" - such as?
I'm not advocating to loop over unknown names. The whole approach is wrong. This is obviously an enumerated collection and should be treated as such. Using magic (including reflection) as I said, may be necessary in some edge cases but should be avoided in all other situations because it undermines readability, accountability, proper documentation and e.g. violates the LoD.
Looping over the names is exactly what everyone else suggested! The OP has anywhere between 1-n variables of unknown name and wants to map them to an array. In the best possible world, he would hardcode all n variables into this array for readability and accountability - thus breaching another OOP pillar, maintainability. As for documentation, is there anything stopping you from flagging it up in whatever doc you're creating?
2

in my system, which doesn't allow me to do

$myPropertyValue = $object->$property;

I still can get to the value of the 'variable' property name with the function below; you can set $property without php complaining about syntax or throwing errors.

<?php
    class MyClass{
    public function getProperty($propertyName){
        $props=get_object_vars($this);
        if (array_key_exists($propertyName,$props)){
            return $props[$propertyName];
        }else{
            return FALSE;
        }
    }
}
?>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.