1.11M Members

Best way to iterate object 'collections'

 
0
 

Hi,

I've got a class in PHP with an array of objects in it.

I need to loop through these objects and call 2 methods on them but I'm not sure of the best approach.

When dealing with arrays, if you use foreach, you can't seem to update the actual array. Example:

$foo = array ("first","second","third");

$x=1;

print_r ($foo);

foreach ($foo as $current){
    $current = $x++;
}

print_r ($foo);

outputs the following:

Array
(
    [0] => first
    [1] => second
    [2] => third
)
Array
(
    [0] => first
    [1] => second
    [2] => third
)

so if $foo contains objects and not simply strings, if I call a method in that object which sets some property, as soon as the foreach moves to the next object in the array that change will be destroyed. This is pointless.

I have devised a possible solution to this as per the below:

$foo = array ("first","second","third");

$x=1;

print_r ($foo);

foreach ($foo as $current => $randomUselessVariable){
    $foo[$current] = $x++;
}

print_r ($foo);

this has the desired output:

Array
(
    [0] => first
    [1] => second
    [2] => third
)
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)

It does however bother me a little that $randomUselessVariable is being created for no good reason and if the object happened to be a large one it might slow down the execution quite badly.

Everything I've found by searching suggests using foreach ($values as $value) and the examples are always a simple getFoo() method and never something that updates the actual value in the array.

Has anyone got a nice happy solution to this or should I just stick with my ugly foreach ($key => $completeWasteOfResources) ?

Thanks for taking the time to read :)

 
0
 
foreach( $array as $index => $value) 
    {
    echo "$index , $value";
    }

0 , first
1 , second
2 , third

 
0
 

Thanks for posting but that does nothing to answer my question.

 
0
 

A general principle is not jumping to coclusions without reading and trying. You wrote :
“so if $foo contains objects and not simply strings, if I call a method in that object which sets some property, as soon as the foreach moves to the next object in the array that change will be destroyed”

This isn’t true for many- many reasons , but lets see it with an example

<?php
class bicycle
{
  private $color; 

  public function setColor($color)
  {
    $this->color = $color; 
  }

  public function getColor()
  {
    return $this->color;
  }
}

$bicyclesArray = array(); 
$bicycle1 = new bicycle(); 
$bicycle1->setColor("purple");
$bicycle2 = new bicycle(); 
$bicycle2->setColor("red");
$bicycle3 = new bicycle(); 
$bicycle3->setColor("black");
$bicyclesArray[] = $bicycle1;
$bicyclesArray[] = $bicycle2;
$bicyclesArray[] = $bicycle3;
echo "before changing the colors:<br/>";
var_dump($bicyclesArray);

foreach ($bicyclesArray as $bicycle)
{
  $bicycle->setColor("blue");
}
echo "<br/>after changing the colors:<br/>";
var_dump($bicyclesArray);
?>

That could be the answer but we will get a bit deeper to it because you say that you “got a class in PHP with an array of objects in it”. If that array of objects inside the parent class is the reason for the existence of it then we are talking for some kind of list of objects. The theory of lists of objects is something quite fascinating but complex in programming and I will stick only to what you are asking and the use of IteratorAggregate interface for it and ArrayIterator Iterator.

<?php
class bicycle
{
  private $color; 

  public function setColor($color)
  {
    $this->color = $color; 
  }

  public function getColor()
  {
    return $this->color;
  }
}

class elementaryList implements IteratorAggregate
{
  private $objectsArray; 

  public function __construct()
  {
    $this->objectsArray = array(); 
  }

  public function getIterator()
  {
    return new ArrayIterator($this->objectsArray);
  }

  public function size()
  {
    return count($this->objectsArray);
  }

  public function add($object)
  {
    $this->objectsArray[] = $object;
  }
}


$bicyclesList = new elementaryList();

$bicycle1 = new bicycle(); 
$bicycle1->setColor("purple");
$bicycle2 = new bicycle(); 
$bicycle2->setColor("red");
$bicycle3 = new bicycle(); 
$bicycle3->setColor("black");

$bicyclesList->add($bicycle1);
$bicyclesList->add($bicycle2);
$bicyclesList->add($bicycle3);

echo "before changing the colors:<br/>";
var_dump($bicyclesList);

if($bicyclesList->size() > 0)
{
  foreach ($bicyclesList as $bicycle)
  {
    $bicycle->setColor("blue");
  }
}

echo "<br/>after changing the colors:<br/>";
var_dump($bicyclesList);
?>
 
0
 

Thanks for taking the time to reply.

That's fascinating and at the same time rather worrying that arrays of one type are treated differently from arrays of another. I tested this further using an array of mixed values.

class bicycle
{
    private $color;
    public function setColor($color)
    {
        $this->color = $color;
    }
    public function getColor()
    {
        return $this->color;
    }
}
$bicyclesArray = array();
$bicycle1 = new bicycle();
$bicycle1->setColor("purple");
$bicycle2 = "red";
$bicycle3 = new bicycle();
$bicycle3->setColor("black");
$bicyclesArray[] = $bicycle1;
$bicyclesArray[] = $bicycle2;
$bicyclesArray[] = $bicycle3;
echo "before changing the colors:<br/>";
var_dump($bicyclesArray);
foreach ($bicyclesArray as $bicycle)
{
    if (is_string($bicycle)){
        $bicycle = "blue";
    } else {
        $bicycle->setColor("blue");
    }
}
echo "<br/>after changing the colors:<br/>";
var_dump($bicyclesArray);

output:

before changing the colors:<br/>array(3) {
  [0]=>
  object(bicycle)#1 (1) {
    ["color":"bicycle":private]=>
    string(6) "purple"
  }
  [1]=>
  string(3) "red"
  [2]=>
  object(bicycle)#2 (1) {
    ["color":"bicycle":private]=>
    string(5) "black"
  }
}
<br/>after changing the colors:<br/>array(3) {
  [0]=>
  object(bicycle)#1 (1) {
    ["color":"bicycle":private]=>
    string(4) "blue"
  }
  [1]=>
  string(3) "red"
  [2]=>
  object(bicycle)#2 (1) {
    ["color":"bicycle":private]=>
    string(4) "blue"
  }
}

so even within the same array 2 elements are treated differently. It would seem that foreach returns either the array element's value or a reference to it depending on the element's type.

Am I being silly here?

Ta
Ben

 
1
 

No you are not , but it has a logic behind it.

When PHP (after PHP 4) passes a variable to a method , if this variable is an object , it passes the reference value (in PHP case the Recourse Id) of it, the same happens to foreach. But not everything in PHP is object, so when this variable is a String or Int it hasn’t a recourse Id to pass, so it passes the value of it. That means that when you iterate through arrays using foreach the handling of the values of each key depends through its type.

 
0
 

Thanks

You
This article has been dead for over six months: Start a new discussion instead
Post:
Start New Discussion
View similar articles that have also been tagged: