PHP array_walk_recursive: two approaches, different result - php

Given the following setup:
$storer = array();
$arr = array(1, 2, 3);
I'm curious why this does not write to $storer...
array_walk_recursive($arr, function($val, $key) {
global $storer;
$storer[] = 'foo';
});
print_r($storer); //no change - empty
..but this does:
array_walk_recursive($arr, function($val, $key) use (&$storer) {
$storer[] = 'foo';
});
print_r($storer); //three items, all 'foo'
Can anyone enlighten me? In a user function I would expect global to provide read/write access.

After pulling my hair out trying to get a flattened array with keys this works:
$result = array();
array_walk_recursive($inputarray,function($v, $k) use (&$result){ $result[$k] = $v; });
$inputarray = $result;
I hope someone finds this and it helps.

Related

PHP - dynamically add dimensions to array

I have a :
$value = "val";
I also have an array :
$keys = ['key1', 'key2', 'key3'...]
The keys in that array are dynamically generated, and can go from 2 to 10 or more entries.
My goal is getting this :
$array['key1']['key2']['key3']... = $value;
How can I do that ?
Thanks
The easiest, and least messy way (ie not using references) would be to use a recursive function:
function addArrayLevels(array $keys, array $target)
{
if ($keys) {
$key = array_shift($keys);
$target[$key] = addArrayLevels($keys, []);
}
return $target;
}
//usage
$keys = range(1, 10);
$subArrays = addARrayLevels($keys, []);
It works as you can see here.
How it works is really quite simple:
if ($keys) {: if there's a key left to be added
$key = array_shift($keys); shift the first element from the array
$target[$key] = addArrayLevels($keys, []);: add the index to $target, and call the same function again with $keys (after having removed the first value). These recursive calls will go on until $keys is empty, and the function simply returns an empty array
The downsides:
Recursion can be tricky to get your head round at first, especially in complex functions, in code you didn't write, but document it well and you should be fine
The pro's:
It's more flexible (you can use $target as a sort of default/final assignment variable, with little effort (will add example below if I find the time)
No reference mess and risks to deal with
Example using adaptation of the function above to assign value at "lowest" level:
function addArrayLevels(array $keys, $value)
{
$return = [];
$key = array_shift($keys);
if ($keys) {
$return[$key] = addArrayLevels($keys, $value);
} else {
$return[$key] = $value;
}
return $return;
}
$keys = range(1, 10);
$subArrays = addARrayLevels($keys, 'innerValue');
var_dump($subArrays);
Demo
I don't think that there is built-in function for that but you can do that with simple foreach and references.
$newArray = [];
$keys = ['key1', 'key2', 'key3'];
$reference =& $newArray;
foreach ($keys as $key) {
$reference[$key] = [];
$reference =& $reference[$key];
}
unset($reference);
var_dump($newArray);

Find Item by key without using eval

I know that eval() is a horrible thing to use, but I couldn't think of a better way to do this.
I have the following method which I want to use to delete items from a multidimensional array, and it should delete the item if it exists.
public function delete(){
$keys = func_get_args();
$str = "";
foreach($keys as $key){
$str .= "['$key']";
}
eval("if(isset(\$_SESSION$str)){unset(\$_SESSION$str);}");
}
To use it I would make a call like so:
$obj->delete("one", "two", "three");
which would be the equivalent to this:
if(isset($_SESSION["one"]["two"]["three"])){
unset($_SESSION["one"]["two"]["three"]);
}
Is there a better way to do this than using eval()?
There is a function like that in Ouzo Goodies:
Arrays::removeNestedKey($_SESSION, ['one', 'two', 'three']);
If you don't want to include the lib, you can take a look at the source code and grab the function itself:
public static function removeNestedKey(array &$array, array $keys)
{
$key = array_shift($keys);
if (count($keys) == 0) {
unset($array[$key]);
} else {
self::removeNestedKey($array[$key], $keys);
}
}
This will achieve what you want:
function delete(){
$keys = func_get_args();
$ref = &$_SESSION;
for($x = 0; $x < sizeOf($keys)-1; $x++) {
$ref = &$ref[$keys[$x]];
}
unset($ref[$keys[sizeOf($keys)-1]]);
unset($ref);
}

PHP - Get a reference to an element from a multidimensional array by using string as key

is there an easy, non-eval-using method for getting a reference to an element of a multidimensional array? The key should be passed as a string.
Here's an example:
getSessionReference('1.4.2', $arrReference);
should return a reference to
$_SESSION['1']['4']['2']
and so a call like
$arrReference['foo'] = 'bar';
would change it to
$_SESSION['1']['4']['2']['foo'] = 'bar'
Any ideas?
Thanks in advance.
$arr[5][6][7] = 111;
$cursor =& $arr;
foreach (explode('.', '5.6') as $key) {
$cursor =& $cursor[$key];
}
var_dump($arr);
var_dump($cursor);
$cursor['foo'] = 5;
var_dump($arr);
var_dump($cursor);
http://codepad.viper-7.com/XUEhMj
or in function form
function & getSessionRef($keyPath) {
$cursor =& $_SESSION;
foreach (explode('.', $keyPath) as $key) {
$cursor =& $cursor[$key];
}
return $cursor;
}
$cursor =& getSessionRef('a.6');
btw - I used the php feature named references in that code, where you see the ampersand like =&.
Use pass-by-reference.
function getReference($key, &$arr)
{
$e = explode('.', $key);
foreach ($_SESSION[$e[0]][$e[1]][$e[2]] as $k => &$v)
$arr[$k] = $v;
}
$arr = array();
getReference("1.4.2", $arr);
p.s.: this does not actually return the reference but it serves your needs.

How to convert a 1-dimensional array into a 2-dimensional array in PHP

I have an array as follows:
$array['a'] = 'Red';
$array['b'] = 'Green';
$array['c'] = 'Blue';
I want to convert it to:
$array['a'][1] = 'Red';
$array['b'][1] = 'Green';
$array['c'][1] = 'Blue';
Is that possible with an existing PHP function or do I need to write my own function?
No, there is no built-in function that can achieve this. However, this is pretty straight-forward with a foreach loop, so I don't see why you need a function:
$result = array();
foreach ($array as $key => $value) {
$result[$key][1] = $value;
}
print_r($result);
If you want a more functional approach, you could use array_walk():
// walks through the original $array and adds a new dimension
array_walk($array, function(&$v, $k){
$v = array(1 => $v);
});
Although, a normal foreach would be more straight-forward and readable.

PHP: Create array of arrays, ignoring empty arrays

I need to create an array of arrays.
I have been using array_map(null,$a,$b,$c) to do this and it works fine, however, it doesn't work if one of the mapped arrays doesn't exist.
To get around this problem I have used:
$myArray= array();
if (isset($a)) {
array_push($myArray,$a);
}
if (isset($b)) {
array_push($myArray,$b);
}
if (isset($c)) {
array_push($myArray,$c);
}
Is there a more elegant/shorter method of writing this?
I've tried applying some functions via array_map($function,$a,$b,$c) but with no luck.
$myArray = array_filter(array($a, $b, $c));
You could use the following function:
function joinArrays(){
$arrays = func_get_args();
$output = array();
foreach($arrays as $array){
if(!empty($array)) array_push($output, $array);
}
return $output;
}
call like: joinArrays($a, $b, $c, etc..);

Categories