Same object property with different values - php

I have a problem occurring in one function, for me it's strange because I thought that the behaviour of objects were different. The function is:
function getMessages($imapCon)
{
$messageHeaders = array();
$tempObj = new stdClass();
$totalMessages = imap_num_msg($imapCon);
for ($i = $totalMessages; $i > 0; $i--)
{
$headers = imap_headerinfo($imapCon, $i);
$tempObj->Unseen = $headers->Unseen;
$tempObj->fromaddress = $headers->fromaddress;
$tempObj->Date = $headers->Date;
$tempObj->Subject = $headers->Subject;
$tempObj->uid = imap_uid($imapCon, $i);
array_push($messageHeaders, $tempObj);
}
return json_encode($messageHeaders);
}
In the json encoded, I get the same values for all properties (Unseen, fromaddress, Date...). The properties are set correct, but the values are duplicated. Why?
If I do something like:
for ($i = $totalMessages; $i > 0; $i--)
{
$tempObj = new stdClass();
...
array_push($messageHeaders, $tempObj);
unset($tempObj);
}
return json_encode($messageHeaders);
}
declaring the object inside the for, it works. But I believe this is a poor fix and nor the right thing to do...

Creating a new $tempObj inside the loop is the right way. When you add this object into array, it's not copied, but a pointer to it is added into the array. Check this documentation - http://php.net/manual/en/language.oop5.basic.php#example-191 (look at the simple assignment, ignore the $reference variable for now).
So you end up with array containing the whole bunch of links pointing to the same object. But if you create a new $tempObj inside the loop, all objects will be different.
Alternatively, you can do this:
array_push($messageHeaders, clone($tempObj));
but although this will equally work in this case, it may not work if the $tempObj would have more complex structure, such as instances of othe classes as properties of $tempObj.
On a side note, in PHP4 your code would work as you expected as PHP4 was copying actual objects on assignment instead of just pointers as PHP5 does.

It looks like you are just pushing a reference into the $messageHeaders array each time, but you are reassigning the data on the same instance. Not sure where you got the idea that it was wrong to create a new $tempObj on each iteration but that is one way you could solve this. Another way would be to just add to the $messageHeaders array directly like this:
$messageHeaders[] = array(
'Unseen' => $headers->Unseen,
'fromaddress' => $headers->fromaddress,
'Date' => $headers->Date,
'Subject' => $headers->Subject,
'uid' => imap_uid($imapCon, $i)
);

Related

In PHP, how can I create and add to an object?

Just so you know I'm working in WordPress. I have an array and want to create an object with only certain values from that array.
Then I have another separate array, I'd like to add to this new object. I might be over complicating things. If I am, please let me know.
Here's what I have so far:
$custom = get_post_custom(); //Gets array of values
$picObject = (object)$custom; //Creates object
$picCount = $custom['picturecount'][0];
for ($x = 1; $x <= $picCount; $x++) {
// This assembles a URL that I want to add to the array.
$finalUrl = $picUrl.$gsi.'&picfilename='.$vin.'_00'.$x.'.jpg';
}
Let me know if you need anything else. Thanks in advance everyone!
If you want to create an object with only some values from your array, you shouldn't cast the array because you'll end up with all of its values. Instead, create a new object and set the values you want:
$array = array(
'foo' => 'bar',
'bar' => 'baz'
);
$object = new stdClass();
$object->bar = $array['bar'];
$object->something_else = 'w00t!';
Casting an array to object (i.e. (object)$array) will get you the same type of object, so you can still use $object->new_property = 'foo'; to add stuff to it.

When is it appropriate to use an ArrayObject instead of an Array

I'm wondering when, if ever it would be appropriate to use an ArrayObject() instead of an Array()? Here's an example i've been working on.
To me i'm thinking a simple array will work, but i found ArrayObject() in the manual and I'm wondering, if it would be better to use one instead of a simple array.
public function calculateTotal(){
if(count($this->items) > 0){
$n = 0;
foreach($this->items as $item){
if($item->size == 'small'){
$k = $item->price->small;
}
if($item->size == 'large'){
$k = $item->price->large;
}
$n += $k * $item->quantity;
}
}else{
$n = 0;
}
return (int) $n;
}
Now I'm confused as to how i should construct the object.
for instance can i construct it with the short array syntax?
$this->items = []; //empty object
or should i construct is as an Array object
$this->items = new ArrayObject(); //empty object
I'm also confused as to how exactly i should push new items to the array.
i have the following function i'm writing:
Also how should i append arrray objects to this object?
is this good?
public function additem($item){
$add = [
'item_id'=>$this->item_id(),
'name'=>$item['name'],
'size',$item['size'],
'quantity'=>$item['quantity'],
'price'=>[
'large'=>$item['price'],
'small'=>$item['price']
]
]
array_push($this->items,$add);
}
or should i instead use ArrayObject::append() or some other method?
I checked the manual and it says this:
public void ArrayObject::append ( mixed $value )
Appends a new value as the last element.
Note:
This method cannot be called when the ArrayObject was constructed from an object. Use ArrayObject::offsetSet() instead.
source http://php.net/manual/en/arrayobject.append.php
The reason i'm asking this now is, later on when needing to delete items from this list how will i find what i'm looking for? can i use in_array() on this object.
I apologize in advance for these questions that might seem dumb to you, but keep in mind I'm still learning some of the more technical things. Thank you
There's nothing in your first snippet that would require ArrayObject. KISS and use simple arrays: array_push($this->items,$add); or $this->items []= $add; are both fine.
As a side note, there's a discrepancy between calculateTotal and add in your code: you have to decide whether you want your item structures to be arrays ($item['price']) or objects ($item->price). My advice is to use arrays, but that's really up to you.

Object pushed to array overites

I've got strange thing, it's probably simple but I can't find a solution for it. Here is part of the code:
$counter = 0;
$autoload_view_instace = new Logic_InvoiceCostData;
$sub_view_cost = array();
foreach($invoceCostData as $data)
{
$counter++;
$parm = $autoload_view_instace->edit_view_data($autoload_view, $data, $counter);
array_push( $sub_view_cost, $parm);
}
The loop calls the edit_view_data method which returns an object with some values. That object should be placed at the end of the array in each iteration without changing values of objects previously added. But after each iteration, all objects in the array have the same value as the newly added object.
apparently the array_push syntax is correct.. and it should work .. however you can do the same thing using.
$sub_view_cost[]=$parm ;
and make sure each time $parm get the correct value

Creating an array in PHP

If I wanted to create an array in PHP with the following format, what would be the best way to approach it? Basically I want to declare the array beforehand, and then be able to add the values to person_id, name and age.
'person_id' => array('name'=>'jonah', 'age'=> 35)
To the first answer #Joe, first of all, your class doesn't support encapsulation since your attributes are public. Also, for someone who doesn't know how to create an array, this concept may be a bit complicated.
For the answer, changing a bit the class provided by #Joe, PHP provide a simple way of using arrays:
If you need many rows for this array, each row has a number, if not, remove the [0] for only one entry.
$persons = array();
$persons[0]['person_id'] = 1;
$persons[0]['name'] = 'John';
$persons[0]['age'] = '27';
Depending on how you want to use it, you could make a simple object:
class Person
{
public $person_id;
public $name;
public $age;
}
$person = new Person; // make the object beforehand
$person->person_id = 123; // their id
$person->name = 'Joe'; // my name
$person->age = 21; // yeah, right
This is virtually identical to an array (in terms of how it's used) except for:
Instead of new array() you use new Person (no brackets)
Instead of accessing items with ['item'] you use ->item
You can start with an empty array:
$arr = Array();
Then add stuff to that array:
$arr['person_id'] = Array();
$arr['person_id']['name'] = "jonah";
$arr['person_id']['age'] = 35;

Duplicate array but maintain pointer links

Suppose I have an array of nodes (objects). I need to create a duplicate of this array that I can modify without affecting the source array. But changing the nodes will affect the source nodes. Basically maintaining pointers to the objects instead of duplicating their values.
// node(x, y)
$array[0] = new node(15, 10);
$array[1] = new node(30, -10);
$array[2] = new node(-2, 49);
// Some sort of copy system
$array2 = $array;
// Just to show modification to the array doesn't affect the source array
array_pop($array2);
if (count($array) == count($array2))
echo "Fail";
// Changing the node value should affect the source array
$array2[0]->x = 30;
if ($array2[0]->x == $array[0]->x)
echo "Goal";
What would be the best way to do this?
If you use PHP 5:
Have you run your code? It is already working, no need to change anything. I get:
Goal
when I run it.
Most likely this is because the values of $array are already references.
Read also this question. Although he OP wanted to achieve the opposite, it could be helpful to understand how array copying works in PHP.
Update:
This behaviour, when copying arrays with objects, the reference to the object is copied instead the object itself, was reported as a bug. But no new information on this yet.
If you use PHP 4:
(Why do you still use it?)
You have to do something like:
$array2 = array();
for($i = 0; $i<count($array); $i++) {
$array2[$i] = &$array[$i];
}
it is some time that I don' write PHP code, but does the code
// Some sort of copy system
$array2 = $array;
actually work?
Don't you have to copy each element of the array in a new one?

Categories