Store array add handle to variable - php

Hey in a recent project I got this working and was quite amazed that such a snipped works.
$parentRef = &$elements[$targetPath]->
{$contentTypeMap[$contentTypeIdMap[$contentTypeId]]};
if(is_array($parentRef)) {
$parentRef = &$parentRef[];
}
$parentRef = $element;
It was quite intuitive that it might work that way but what exactly is
$parentRef[] returning to make this work?
If I var_dump it, i get null.
Here is a simplified example which seems to work.
<?php
$arr = [1, 2];
$ref = &$arr[];
$ref = 3;
foreach($arr as $n) {
echo $n;
}
This example returns 123 just to verify that it works.

In your example $arr[] will create new element in array with NULL value. The ampersand is reference to this position, so when you store something to $ref, it will be stored in this new position, because $ref is just reference (something like pointer, but its not pointer!) to this new element in array

Related

Issue with modifying array in foreach and understading why

I always did something like
e.g. from my last project in Laravel
foreach( $sections as $section )
{
$section->date = Carbon::parse($section->date)->diffForHumans();
}
And it worked well. Never problem with that, array was modified as I wanted
But now I did this
$events = $this->events;
foreach($events as $event)
{
$date = new \DateTime($event['date']);
$event['date'] = (int)$date->format('d');
echo $event['date'];
var_dump($event);
}
var_dump($events);
$this->events = $events;
And it doesn't work as I want, different values inside loop and outside loop.
I was looking what is bad and I found what it is about, to give & or do foreach $key => $value...
But it would be okay.
But it isn't.
Because I know. I remember. I did many times just something like
foreach($a as $b)
{
$b = .......
}
And it worked. But now it isn't.
So I don't understand. But I have to and want to.
I was searching for answer, but can find it.
Why for one time it works for me like that, and other time doesn't work and I need apersand or key => value playing?
Please give me understanding <3
Why one time it is working but another not.
foreach iterates over a copy of the array, so modifications to the array elements are only made to that temporary copy unless you create a reference:
foreach($a as &$b) {
$b = 'something';
}
Or modify the original array by key:
foreach($a as $k => $b) {
$a[$k] = 'something';
}
For an array of objects, the array is a copy but the objects in the copy are references to the original array. So modifications to the objects in the copy are reflected in the original array:
foreach($a as $b) {
$b->var = 'something';
}

Same object property with different values

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)
);

PHP: use return as key / value pair for a parent array

Well, after I rewrote my problem description 2 times i'll do it somehow less abstract now.
I need a way to return data within an array so that this array accepts this returned data as native key / value pair.
Illustration:
simple array:
$a = array('a' => 'b');
I could access the value of 'a' by simply calling $a['a']... clearly
I now need a way to exactly get this result via a function call or hack or something!
something like
$a = array(foo('a','b'));
the problem is, when "foo" return an array, the structure of my $a (array) will look like this:
array(array('a','b')) and not like array('a' => 'b')
and will prevent me from being able to access the data via $a['a']
The reason I need this is that I instance objects on demand within this array definition and also modify these instances on the fly, but I do need 2 different returns (of functions) of one and the same object and don't want to copy past half the initialization. Further more I don't want to first declare object instances outside the array because this would be a absolute overkill and would perfectly destroy all readability.
So.. is there a possibility to extract returned values to native language features?
PS. I also don't want to iterate over the array to re-process the data
$a = foo('a','b');
with
function foo($x,$y) {
return array($x => $y);
}
If foo() is returning an array, why not;
$a = foo('a','b');
Seems simple enough, right?
Easiest way:
$a[]= foo();
function foo() {
return array(1,2);
}
Or use reference:
$value = NULL;
$a = array(foo($value), $value);
with
function foo(&$value) {
$value = 'b';
return 'a';
}
function foo($key) {
$r = array(
'a' => 'b',
$key2 => $value2,
$key3 => $value3,
$key4 => $value4
// ...
);
return $r[$key];
}
$a = foo('a'); // means $a = 'b';
Do it solves your problem ?

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?

Make 1d Array from 1st member of each value in 2d Array | PHP

How can you do this? My code seen here doesn't work
for($i=0;i<count($cond);$i++){
$cond[$i] = $cond[$i][0];
}
It can be as simple as this:
$array = array_map('reset', $array);
There could be problems if the source array isn't numerically index. Try this instead:
$destinationArray = array();
for ($sourceArray as $key=>$value) {
$destinationArray[] = $value[0]; //you may want to use a different index than '0'
}
// Make sure you have your first array initialised here!
$array2 = array();
foreach ($array AS $item)
{
$array2[] = $item[0];
}
Assuming you want to have the same variable name afterwards, you can re-assign the new array back to the old one.
$array = $array2;
unset($array2); // Not needed, but helps with keeping memory down
Also, you might be able to, dependant on what is in the array, do something like.
$array = array_merge(array_values($array));
As previously stated, your code will not work properly in various situation.
Try to initialize your array with this values:
$cond = array(5=>array('4','3'),9=>array('3','4'));
A solution, to me better readable also is the following code:
//explain what to do to every single line of the 2d array
function reduceRowToFirstItem($x) { return $x[0]; }
// apply the trasnformation to the array
$a=array_map('reduceRowTofirstItem',$cond);
You can read the reference for array map for a thorough explanation.
You can opt also for a slight variation using array_walk (it operate on the array "in place"). Note that the function doesn't return a value and that his parameter is passed by reference.
function reduceToFirstItem(&$x) { $x=$x[0]; }
array_walk($cond, 'reduceToFirstItem');
That should work. Why does it not work? what error message do you get?
This is the code I would use:
$inArr;//This is the 2D array
$outArr = array();
for($i=0;$i<count($inArr);$i++){
$outArr[$i] = $inArr[$i][0];
}

Categories