PHP Foreach on array of objects - php

Why, if I have array of objects like this:
class testClass {
private $_x = 10;
public function setX($x) {
$this->_x = $x;
}
public function writeX() {
echo $this->_x . '<br />';
}
}
$t = array();
for ($i = 0; $i < 10; $i++) {
$t[] = new testClass();
}
print_r($t);
I can iterate by foreach like this:
foreach ($t as $tt) {
$tt->y = 7;
$tt->setX($counter);
$counter+=100;
}
print_r($t);
Or this:
foreach ($t as &$tt) {
$tt->y = 7;
$tt->setX($counter);
$counter+=100;
}
print_r($t);
And result will be equal? But if i have scalar values in array, they can only be modified by ($arr as &$v), $v only by reference ?

It depends on whether you're using PHP5 or an earlier version.
In PHP5, same thing because it is an array of objects. (Not the same thing for other types.)
In PHP4, not the same thing. (But then again, the second one will complain about a syntax anyway.)

Related

PHP Variable Variables within setter function

I am trying to achieve a way to define an indefinite, but not infinite number of variables, to be used to create objects. I have tried a couple of ways to try this but i cant seem to wrap my head around this.
Here is what i came up with:
$aCount= 0;
$Foo = "Bar".$aCount;
$$Foo = array("Data1"=>NULL, "Data2"=>NULL);
function getBarData1() {
return ${$Foo}['Data1'];
}
function getBarData2() {
return ${$Foo}['Data2'];
}
function setBarData($newBarData1, $newBarData2) {
${$Foo}['Data1'] = $newBarData1;
${$Foo}['CONTENT'] = $newBarData2;
$aCount++;
}
setBarData('First', 'Line');
setBarData('Second', 'Dot');
setBarData('Third', 'Dash');
for($aCount == $aCount; $aCount > -1; $aCount--) {
echo getBarData1() ."\n";
echo getBarData2() ."\n";
}
Any help would be greatly appreciated.
You are heading two problems:
variable scope
value of variable $Foo is static and never change - value is always: Bar0 even when you change $aCount because the value is just a string
working example:
<?php
$aCount= 0;
$Foo = function(){ global $aCount; return "Bar".$aCount; };
${$Foo()} = array("Data1"=>NULL, "Data2"=>NULL);
function getBarData1() {
global $Foo, ${$Foo()};
return ${$Foo()}['Data1'];
}
function getBarData2() {
global $Foo, ${$Foo()};
return ${$Foo()}['Data2'];
}
function setBarData($newBarData1, $newBarData2) {
global $aCount, $Foo, ${$Foo()};
${$Foo()}['Data1'] = $newBarData1;
${$Foo()}['Data2'] = $newBarData2;
$aCount++;
}
setBarData('First', 'Line');
setBarData('Second', 'Dot');
setBarData('Third', 'Dash');
$aCountTotal = $aCount;
for($i = 0; $i < $aCountTotal; $i++) {
$aCount = $i;
echo getBarData1() ."\n";
echo getBarData2() ."\n";
}
in this case you should use array instead, variable-variable is really usefull in rare cases
array example:
<?php
$arr = array();
function getBarData1($index) {
global $arr;
return $arr[$index]['Data1'];
}
function getBarData2($index) {
global $arr;
return $arr[$index]['Data2'];
}
function setBarData($newBarData1, $newBarData2) {
global $arr;
$arr[] = ['Data1' => $newBarData1, 'Data2' => $newBarData2];
}
setBarData('First', 'Line');
setBarData('Second', 'Dot');
setBarData('Third', 'Dash');
for($i = 0; $i < count($arr); $i++) {
echo getBarData1($i) ."\n";
echo getBarData2($i) ."\n";
}
better than using global variable in functions is passing data through parameters like:
<?php
$arr = array();
function getData1($array, $index) {
return $array[$index]['Data1'];
}
function getData2($array, $index) {
return $array[$index]['Data2'];
}
// reference to $array because we want to change the value
function setData(&$array, $newBarData1, $newBarData2) {
$array[] = ['Data1' => $newBarData1, 'Data2' => $newBarData2];
}
setData($arr, 'First', 'Line');
setData($arr, 'Second', 'Dot');
setData($arr, 'Third', 'Dash');
for($i = 0; $i < count($arr); $i++) {
echo getData1($arr, $i) ."\n";
echo getData2($arr, $i) ."\n";
}

PHP - Modify array value by reference inside object

How can I pass a value of an array by reference to modify its value inside an object? I've tried it with the & operator at public function f(&$z) {.
<?php
class C {
private $a;
public function f($z) {
foreach ($z as $i => $v) {
$v = 8888;
}
}
}
$p = 4;
$obj = new C();
$obj->f(array('key'=>$p));
echo $p;
?>
I would like to set the 8888 value to the $p variable.
The fiddle: http://codepad.org/RvKU4hY1
You have to use references when you 1) create the array, 2) iterate over it:
<?php
class C {
private $a;
public function f($z) {
foreach ($z as $i => &$v) {
$v = 8888;
}
}
}
$p = 4;
$obj = new C();
$obj->f(array('key'=>&$p));
echo $p;
?>
Only slightly different to georg, you can do it this way;
<?php
class C {
private $a;
public function f($z) {
foreach ($z as $i => $v) {
$z[$i] = 8888;
}
}
}
$p = 4;
$obj = new C();
$result = array('key'=> &$p);
$obj->f($result);
echo $p;
?>
Here the code with explanation:
<?php
class C {
private $a;
public function f(&$z) { // we receive a pointer
foreach ($z as $i => $v) {
// here you overwrite $v, even if it a pointer in foreach
// It has mean when you want to do unset($v); here
// $v = 8888;
$z[$i] = 8888;
}
}
}
$p = 4;
$obj = new C();
$param = array('key'=>$p);
$obj->f($param);
echo $p;

How to create array of objects for a class in php using foreach?

I have a php class like
class fiber {
public $name
}
$array = array('1','2','3');
i need to create three object for the class fiber
i tried the following
foreach($array as $counts) {
$obj = new fiber();
}
but its not working how to create three objects for a class using foreach
You're overwriting $obj each iteration. Instead, do this:
$myArray = array();
foreach($array as $counts) {
array_push($myArray, new fiber());
}
Now you can access each fiber with $myArray[0] etc.
Here's a more complete and generic example (note the use of [] isn't supported before php 5.4).
class Fiber {
private $x;
public function __construct($x) {
$this->x = $x;
}
public function getX() {
return $this->x;
}
}
$x = [1,2,3];
$Fibers = [];
foreach($x as $v) {
$Fibers[]= new Fiber($v);
}
echo $Fibers[0]->getX(); //1
echo $Fibers[1]->getX(); //2
echo $Fibers[2]->getX(); //3
I really prefer $array[]= 'value' over array_push($array, 'value');
This way you'd replace your current array values with new fiber class objects:
$array = array('1','2','3');
foreach($array as &$val) {
$val = new fiber();
}
Or you can skip the part where you fill the array and do the following:
$array = array();
for ($i = 0; $i < 3; $i++)
$array[$i] = new fiber();
You could do it like this:
$index = 0;
foreach($array as $counts) {
${"obj$index"} = new fiber();
$index++;
}
And you will have three objects $obj0, $obj1, $obj2.

Why is passing by reference slower in this code?

I've encountered something that seems like a strange performance problem. Running this code:
<?php
function test_ref(&$test)
{
for ($i = 0; $i < 100000; $i++)
{
$foo = "s" . rand(1, 1000);
if (!array_key_exists($foo, $test))
{
$test[$foo] = array();
}
$test[$foo][] = rand(1, 10);
}
}
function test()
{
$test = array();
for ($i = 0; $i < 100000; $i++)
{
$foo = "s" . rand(1, 1000);
if (!array_key_exists($foo, $test))
{
$test[$foo] = array();
}
$test[$foo][] = rand(1, 10);
}
return $test;
}
$scriptstart = microtime(true);
$test = array();
test_ref($test);
$sum = 0;
foreach ($test as $key => $val)
{
foreach ($val as $val2)
{
$sum += $val2;
}
}
echo "sum " . $sum . "<br>";
$scriptelapsed = microtime(true) - $scriptstart;
echo "time taken " . $scriptelapsed . "<br>";
$scriptstart = microtime(true);
$test = test();
$sum = 0;
foreach ($test as $key => $val)
{
foreach ($val as $val2)
{
$sum += $val2;
}
}
echo "sum " . $sum . "<br>";
$scriptelapsed = microtime(true) - $scriptstart;
echo "time taken " . $scriptelapsed . "<br>";
?>
I get these results:
sum 548521
time taken 12.37544798851
sum 551236
time taken 0.29530310630798
What's going on here? It seems to be connected to the fact that I insert sub-arrays into the array, though I don't see why passing by reference should be that much slower.
(this is on PHP Version 5.3.3-7+squeeze14 with Suhosin Patch 0.9.9.1)
(edit: fixed using of unset variables, still the same result)
You're accessing values from another scope - that's always slower than only using ones that are defined within the function itself. Here's a nice blog post explaining it, even though that's not its primary topic: PHP internals: When does foreach copy?
It is just my guess but I think we could explain it like this:
when using no reference a local variable is created (that is directly pointing to a memory) and the loop goes like:
$i = 0; $foo = 499; $test[499] = array(); $test[499][] = 2; "commit" directly to a memory
finaly, the value $test is then returned - reading directly from the memory pointer
when using referenced value, the variable passed is like a pointer to a pointer (that is finally pointing to a memory)
in this case the loop looks like:
$i = 0; $foo = 354; $test[354] = array(); $test[354][] = 7; "commit" to a memory via pointer to a memory pointer
I guess therefore there is at least one more step neccessary when working with referenced variables...

Initialising an array of objects

Program that tests the rand function is an example:
<?php
class number {
function number() {
$occurences=0;
}
public $occurences;
public $value;
}
$draws = 5000;
$numOfInts = 10;
//$integers = array();
$integers [] = new number();
//initialising loop
for($i=0;$i<=$numOfInts;$i++)
$integers[$i]->$value = $i; //debugger points here
for($i=0;$i<$draws;$i++) {
$integers[rand(0,numOfInts)]->$occurences++;
}
foreach($integers as $int)
printf("%5d %5d <br/>",$int->$value,$int->$occurences);
?>
Errors on the WAMP server:
Undefined variable: value in C:\path\index.php on line 31
Fatal error: Cannot access empty property in C:\path\index.php on line 31
What caused them and how to fix it? I suppose that the $integers is declared incorrectly.
You should access members of an object with this syntax:
$integers[$i]->value
$integers[$i]->occurences;
However you have to initialize your array first as well which means un-comment the initial line to
$integers = array();
As a matter of fact you are not using the better OOP style which would change your data structure like this:
class Number {
private $value;
private $occurences = 0;
public function __construct($value = 0) {
$this->value = $value;
}
public function getValue() {
return $this->number;
}
public function addOccurence() {
$this->occurences++;
}
public function getOccurences() {
return $this->occurences;
}
}
You would then access the members like this:
// init part
$integers = array();
for($i = 0; $i < $numOfInts; $i++) {
$integers[] = new Number($i);
}
// draws part
for($i=0; $i < $draws; $i++) {
$integers[rand(0,$numOfInts-1)]->addOccurence();
}
// print part
foreach($integers as $number) {
printf("%5d %5d<br />", $number->getValue(), $number->getOccurences());
}
Why?
//$integers = array();
$integers [] = new number();
Should just be
$integers = array();
for($i=0;$i<=$numOfInts;$i++) {
$integers[$i] = new number();
}
There are no typed arrays in PHP

Categories