Set variable in foreach loop and pass by reference - php

I was playing with PHP recently and wanted to assign variable in foreach loop and pass value by reference at the same time. I was a little bit surprised that didn't work. Code:
$arr = array(
'one' => 'xxxxxxxx',
'two' => 'zzzzzzzz'
);
foreach ($foo = $arr as &$value) {
$value = 'test';
}
var_dump($foo);
Result:
array(2) { ["one"]=> string(8) "xxxxxxxx" ["two"]=> string(8) "zzzzzzzz" }
The following approach obviously does work:
$arr = array(
'one' => 'xxxxxxxx',
'two' => 'zzzzzzzz'
);
$foo = $arr;
foreach ($foo as &$value) {
$value = 'test';
}
var_dump($foo);
Result:
array(2) { ["one"]=> string(4) "test" ["two"]=> &string(4) "test" }
Does someone know why those snippets are not equivalent and what is being done behind the scenes?

$foo = $arr is trans by value, not reference, you should use $foo = &$arr. You can refer to Are arrays in PHP passed by value or by reference?
try this, live demo.
$arr = array(
'one' => 'xxxxxxxx',
'two' => 'zzzzzzzz'
);
foreach ($foo = &$arr as &$value) {
$value = 'test';
}
var_dump($foo);

foreach ($foo = $arr as &$value) {
$value = 'test';
}
first you assign the value of $arr[0] to $foo[0] then take that value and make that value = 'test' (this will not change $arr or $foo values "useless statement")
But here
$foo = $arr;
foreach ($foo as &$value) {
$value = 'test';
}
first you asign $arr to $foo
then go to for each statement , get the values of $foo and modify it
ex: $foo[0]='test' , $foo[1]='test' ...

Related

PHP: Detecting references in $GLOBALS

I have a simple way to detect references in an array (For debugging purposes)
First I clone the array with array_values and then I alter the clone and look for changes in the original. If it's changed that element is a reference.
Short example:
<?php
$a = [
'a' => 'b',
2 => 3,
];
$b = ['wow'];
$a['ref'] = &$b;
function getrefs($array) {
$marker = uniqid();
$copy = array_values($array);
$i = 0;
$return = [];
foreach ($array as $key => &$val) {
$stash = $val;
$copy[$i] = $marker;
if ($val === $marker) {
$val = $stash;
$return[] = $key;
}
$i++;
}
return $return;
}
var_dump($a);
var_dump(getrefs($a));
The problem is that when I try to use this on $GLOBALS it's not working, and I can't figure out why. Everything in $GLOBALS should be a reference by all rights.
Is $GLOBALS just so strange that it's the only array where array_values won't correctly copy references?
It's a possibility that you're not accounting for recursion. The built-in PHP function:
var_dump($GLOBALS);
Will have the following output
array(7) {
["_GET"]=>
array(0) {
}
["_POST"]=>
array(0) {
}
["_COOKIE"]=>
array(1) {
["PHPSESSID"]=>
string(26) "od602et6qcfj6pa3pkjtl8go57"
}
["_FILES"]=>
array(0) {
}
["GLOBALS"]=>
*RECURSION*
["_SESSION"]=>
&array(0) {
}
}

PHP Str_replace is not working in foreach loop

Here is my code.
I am trying to get inspect link for steam item. I have tried to use preg_replace but no luck either.
$API_link = sprintf("http://steamcommunity.com/id/*steamid*/inventory/json/730/2?trading=1");
$json = file_get_contents($API_link);
$json_output = json_decode($json);
$result = $json_output;
$link = array();
$id = array();
foreach($result->rgDescriptions AS $item){
$empty = array();
$newstring = $item->actions[0]->link;
if($newstring == NULL){
continue;
} else {
$empty['link'] = $newstring;
array_push($link, $empty);
}
}
foreach($result->rgInventory AS $inventory){
$empty = array();
if($inventory->instanceid == 0){
continue;
} else {
$empty['id'] = $inventory->id;
array_push($id, $empty);
}
}
$array = array_merge($id, $link);
foreach($array AS $final){
$assetid = "%assetid%";
echo str_replace($assetid, $final['id'], $final['link']);
}
}
But its not working. Please see if you can help.
As I can see you have array of arrays:
// bracket squares equivalent of array() keyword PHP >=v5.4
// here is
// $link = array(['link'=>'url'],['link'=>'url'])
// $id = array(['id'=>'id'],['id'=>'id'])
// result will be:
// array(['link']=>'url'],['link'=>'url'],['id'=>'id'],['id'=>'id'])
$array = array_merge($id, $link);
foreach($array AS $final){
// here is the first $final
// array('link'=>'url')
$assetid = "%assetid%";
// but here is we try to get
// 'id' and 'link'
echo str_replace($assetid, $final['id'], $final['link']);
}
I think it's some kind of mistake.
Ok, some test script:
<?php
$a = array( array('link'=>'hello1'), array('link'=>'hello2'));
$b = array( array('id'=>'id0'), array('id'=>'id1'));
$c = array_merge($a, $b);
var_dump($c);
result:
array(4) {
[0] =>
array(1) {
'link' =>
string(6) "hello1"
}
[1] =>
array(1) {
'link' =>
string(6) "hello2"
}
[2] =>
array(1) {
'id' =>
string(3) "id0"
}
[3] =>
array(1) {
'id' =>
string(3) "id1"
}
}
array_merge doesn't mix your associative arrays between them nether all nor particular item (I hope I explain it correct)
of course
foreach ($c as $item) {
var_dump($item);
}
will enumerate all the items one by one
array(1) {
'link' =>
string(6) "hello1"
}
array(1) {
'link' =>
string(6) "hello2"
}
array(1) {
'id' =>
string(3) "id0"
}
array(1) {
'id' =>
string(3) "id1"
}
and there is no array that has both of them (link and id) in the item
This script can't associate link and id properly, cause some of links can be skipped by continue, some of id also can be skipped. And it will be just a random list of available information. You can stuck in the next situation:
- $links has first 10 links
- $id has 3,4,5,7,9,11
It's just a list. Even if you have only this pure info (no other details), you can't properly associate it between of them by using shown source.
Here is minimum 1 simple solutions:
don't skip, don't merge, just add an empty array, and your final loop will be like this:
$assetid = "%assetid%";
for ($link as $key=>$final) {
if (count($final) && count($id[$key])) {
echo str_replace($assetid, $id[$key]['id'], $final['link']);
} else {
// some of needed arguments absent
}
}
Description not enough. Maybe try dump some variables?
foreach($array AS $final){
$assetid = "%assetid%";
//Check what is in $final
var_dump($final);
echo str_replace($assetid, $final['id'], $final['link']);
}

PHP - Use an Array to loop through a second Array

Using explode('<br>',$String) I have an Array1 with sub-Strings.I want to use an Array2 as needles to loop through Array1 and if a Sub-String is found return Array2 values.
Example:
$Array1 { [0]=> string(3) "red"
[1]=> string(4) "Blue"
[3]=> string(5) "Black" };
$Array2 [
'red' => "Red",
'Yellow' => "Yellow"];
What is the best method/function to approach this task. In the example above the Array1 ( Haystack) has a substring "red" , I want to be able to define Key => values in Array2 to use as needles and when for example a certain Key is found return its value.
// Output above
"Red"
Thanks
You can do it with a simple foreach loop
function getColorOrSomething(&$array1, &$array2){
foreach($array2 as $key=>$value)
if(in_array($key, $array1))
return $value;
return null; //no match found
}
and then of course call the function with the 2 arrays
$selected = getColorOrSomething($array1, $array2);
You can use a nested loop like this:
$key = "";
$value = "";
foreach( $Array1 as $ar1 ) {
foreach( $Array2 as $ak2=>ar2 ) {
if( preg_match("/" . $ak2 . "/", $ar1) ) {
$key = $ak2;
break;
}
if( $key != "" ) {
$value = $ar1;
break;
}
}
}
echo "Key: " . $key . " & Value: " . $value;
Like so..

Strange foreach behaviour after an object casting

I get stuck with a strange PHP behaviour after a cast. Here is the code :
$obj = new stdClass();
$obj->{'0'} = "test";
$array = (array)$obj;
var_dump($array);
This code will output :
array(1) { ["0"]=> string(4) "test" }
Absolutely normal.
Now I add some code :
foreach ($array as $key => $value) {
$array[$key] = strtoupper($value);
}
var_dump($array);
This code outputs :
array(2) {
["0"]=>
string(4) "test"
[0]=>
string(4) "TEST"
}
Why my $key casted to int ?
If I try a simpler example :
$array = array("0" => "test");
foreach ($array as $key => $value) {
$array[$key] = strtoupper($value);
}
var_dump($array);
This will output :
array(1) { [0]=> string(4) "TEST" }
Does somebody know why there is a cast of my $key to int ?
Update
I tried to force to cast my key to string :
$array["{$key}"] = $value;
and
$array[(string)$key] = $value;
But they are inserted as int. So my question should be : is there a way to insert keys as string into an array?
I know that I can solve my problem by using a second array and dismiss strings :
$obj = new stdClass();
$obj->{'0'} = "test";
$array = (array)$obj;
$array2 = array();
foreach ($array as $key => $value) {
$array2[$key] = strtoupper($value);
}
But it would be nice to make it in a more beautiful way, conserving data type (and avoiding duplicating entries while iterating them as previously demonstrated).
From the PHP manual:
Strings containing valid integers will be cast to the integer type. E.g. the key "8" will actually be stored under 8. On the other hand "08" will not be cast, as it isn't a valid decimal integer.
#cHao found a clean and working solution to convert an object to an array without foreach() matters. My example becomes :
$array = array();
$obj = new stdClass();
$obj->{'0'} = "test";
foreach ($obj as $key => $value) {
$array[$key] = strtoupper($value);
}
stdClass is iterable.
Thank you!

change key of the multi-array

Have an array:
$a =array[
"param1"=>[]
"param2"=>[]
"param3"=>[]
]
function def($param){
return $param.date();
}
want return a new array
$a =array[
def(param1)=>[]
def(param2)=>[]
def(param3)=>[]
]
anybody know how to do this?
Do you mean something like this?
This is a pretty lengthy (and dirty) suggestion and there's probably a better way using one of PHP's array methods, but here goes:
$array = array('123' => 'should be 6', '14' => 'should be 5', '12' => 'should be 3');
$new_array = array();
foreach ($array as $key => $val) {
$key_exp = str_split($key);
$new_key = 0;
foreach ($key_exp as $key_int) $new_key += $key_int;
$new_array[$new_key] = $val;
}
Gives this output as expected:
array(3) {
[6]=>
string(11) "should be 6"
[5]=>
string(11) "should be 5"
[3]=>
string(11) "should be 3"
}
Note that you may, and probably will, run into key collisions using this method.
Like so:
$out_array = array_fill_keys(array_map(function($in) {
// do stuff you need
return $out;
}, array_keys($in_array)), array());

Categories