array_map strtolower() expects parameter 1 to be string - php

I've got this error Warning: strtolower() expects parameter 1 to be string, array given..
I don't know how I've got my error.. Please help thanks!
$mypages = array(
'Pages' => array('page' => array('view_all_pages', 'add_page', 'dashboard'),
'test' => array('test1', 'test2')),
'Users' => array('vieW_all_users', 'add_user'));
foreach($mypages as $keys => $key):
if(is_array($key)):
$key = array_map('strtolower' ,$key);
endif;
endforeach;

foreach is a loop that will gives you first level of key=>value pairs of an array.
foreach($mypages as $keys => $key){
echo "Key : $keys \n";
echo "Value : ";var_dump($key);
}
will output :
Key : Pages
Value : array('page' => array('view_all_pages', 'add_page', 'dashboard'), 'test'=> array('test1', 'test2')),
Key : Users
Value : array('vieW_all_users', 'add_user')
To make it work, you need to check if the value is an array.
function strtolowerArray(&$arr){
foreach($arr as $k=>$v){
if(is_array($v)){
$arr[$k] = strtolowerArray($v);
}
else if(is_string($v)){
$arr[$k] = strtolower($v);
}
else{
throw new \LogicException("The value is neither a string nor an array");
}
}
return $arr;
}
$mypages = array(
'Pages' => array(
'page' => array('view_ALL_pages', 'aDD_page', 'DaShbOArd'),
'test' => array('test1', 'TEST2')
),
'Users' => array('vieW_all_users', 'aDd_uSer')
);
var_dump(strtolowerArray($mypages));
The '&' in front of the strtolowerArray's parameter means we pass teh variable by reference. If anychanges happens to this variables inside strtolowerArray function's scope, then it will be reflected into the parent scope.

$mypages['Pages']['page'] does not contain a string that can be passed to strtolower().
You should debug by dumping $key inside the loop.

You have arrays in your arrays yo!
You have to iterate into the arrays before asking for (and trying to convert) the values.
Try walking through the array conditionally e.g.
//pseudo
func myRecursion($data = array()) {
foreach($data as $value) {
if(is_array($value)) {
$data = myRecusion($data[$value]);
} else {
//its not an array so do your thing
}
}
return($data);
}

Related

Passing an array copy to a function expecting a reference

I have a loop of the following kind:
foreach ($values as $key => $value) {
$attrs = array('NAME' => $key);
myproc ($attrs);
......
}
Where in myproc the first parameter is defined by reference:
function myproc (& attrs) { .... }
myproc adds the passed value to some structure.
The trouble with this is that at loop end, all the arrays added to the generated structure contains the same value, the last value extracted from the loop.
I tried also something like this :
foreach ($values as $key => $value) {
$attrs = array('NAME' => $key);
$copy = $attrs;
myproc ($copy);
......
}
but the result is the same. I'not allowed to modify the procedure. Any suggestions?
Based on the comment below your question, it seems that the problem is that you are passing a reference and this reference gets updated in the loop, leading to updates in the object you are generating in your function.
To avoid this, you need to unset the variable after the function call so that the link between the value in your object and the referenced variable is broken:
foreach ($values as $key => $value) {
$attrs = array('NAME' => $key);
myproc ($attrs);
// unset the variable so that newer values of it will have no effect
// on the object generated in `myproc`
unset($attrs);
......
}
Also see the manual.
<?php
foreach(['red','pink','green'] as $colour) {
$attrs = ['colour' => $colour];
if(colourToAction($attrs)) {
$results[] = $attrs;
}
}
var_export($results);
function colourToAction(&$attrs) {
$actions = ['red'=>'stop','amber'=>'wait', 'green' => 'go'];
if(isset($attrs['colour']) && isset($actions[$attrs['colour']])){
$attrs['action'] = $actions[$attrs['colour']];
return true;
}
}
Output:
array (
0 =>
array (
'colour' => 'red',
'action' => 'stop',
),
1 =>
array (
'colour' => 'green',
'action' => 'go',
),
)

Loop over one array as if it was a multidimensional array

I have an array like:
$array = array(
'name' => 'Humphrey',
'email' => 'humphrey#wilkins.com
);
This is retrieved through a function that gets from the database. If there is more than one result retrieved, it looks like:
$array = array(
[0] => array(
'name' => 'Humphrey1',
'email' => 'humphrey1#wilkins.com'
),
[1] => array(
'name' => 'Humphrey2',
'email' => 'humphrey2#wilkins.com'
)
);
If the second is returned, I can do a simple foreach($array as $key => $person), but if there is only one result returned (the first example), I can't run a foreach on this as I need to access like: $person['name'] within the foreach loop.
Is there any way to make the one result believe its a multidimensional array?
Try this :
if(!is_array($array[0])) {
$new_array[] = $array;
$array = $new_array;
}
I would highly recommended making your data's structure the same regardless of how many elements are returned. It will help log terms and this will have to be done anywhere that function is called which seems like a waste.
You can check if a key exists and do some logic based on that condition.
if(array_key_exists("name", $array){
//There is one result
$array['name']; //...
} else {
//More then one
foreach($array as $k => $v){
//Do logic
}
}
You will have the keys in the first instance in the second yours keys would be the index.
Based on this, try:
function isAssoc(array $arr)
{
if (array() === $arr) return false;
return array_keys($arr) !== range(0, count($arr) - 1);
}
if(isAssoc($array)){
$array[] = $array;
}
First check if the array key 'name' exists in the given array.
If it does, then it isn't a multi-dimensional array.
Here's how you can make it multi-dimensional:
if(array_key_exists("name",$array))
{
$array = array($array);
}
Now you can loop through the array assuming it's a multidimensional array.
foreach($array as $key => $person)
{
$name = $person['name'];
echo $name;
}
The reason of this is probably because you use either fetch() or fetchAll() on your db. Anyway there are solutions that uses some tricks like:
$arr = !is_array($arr[0]) ? $arr : $arr[0];
or
is_array($arr[0]) && ($arr = $arr[0]);
but there is other option with array_walk_recursive()
$array = array(
array(
'name' => 'Humphrey1',
'email' => 'humphrey1#wilkins.com'
),
array(
'name' => 'Humphrey2',
'email' => 'humphrey2#wilkins.com'
)
);
$array2 = array(
'name' => 'Humphrey2',
'email' => 'humphrey2#wilkins.com'
);
$print = function ($item, $key) {
echo $key . $item .'<br>';
};
array_walk_recursive($array, $print);
array_walk_recursive($array2, $print);

Strange behavior for arrays passed by reference

I've just got an unexpected result for a simple function which has an argument passed by reference.
Let's presume we have the following arrays:
$arr = array(
'Test' => 1,
'OtherKey' => 2,
);
$keyTranslation = array(
'OtherKey' => 'other_key',
'Test' => 'test',
);
The $keyTranslation array might not have the keys defined in the same order as the $arr. This is just to explain the need of the function.
and the following function:
function test(&$arr, $keyTranslation) {
foreach ($arr as $key => $value) {
$arr[$keyTranslation[$key]] = $value;
unset($arr[$key]);
}
}
The unexpected result is when simply call the function having the arrays above as arguments:
test($arr, $keyTranslation);
What I was expected?
array(2) {
["test"]=>
int(1)
["other_key"]=>
int(2)
}
What I've got?
NOTICE Undefined index: test on line number 10
NOTICE Undefined index: other_key on line number 10
NOTICE Undefined index: on line number 10
array(0) { }
Why was this happened?
Because each time I am adding a new value to the passed by reference array, the loop is iterating also over that value and unset it.
The question
Is this normal? or it is a bug in PHP?
This is what I would use as it seems a bit dodgy to be setting & unsetting elements of an array while foreaching through it...
function test(&$arr, $keyTranslation) {
$newarr = array();
foreach ($arr as $key => $value) {
$newarr[$keyTranslation[$key]] = $value;
}
$arr = $newarr; // Not sure if you'd have to unset $arr first...
}
Make sure you test if the translated key exists :
<?php
$arr = [ 'Foo' => 1, 'Bar' => 2 , 'dont_change' => 3, ];
$trans = [ 'Foo' => 'bar', 'Bar' => 'foo', 'Foobar' => 'foobar', ];
function test(&$arr, $trans) {
foreach($arr as $key => $value) {
if (!isset($trans[$key])) continue;
$arr[$trans[$key]] = $value;
unset($arr[$key]);
}
}
test($arr, $trans);
print_r($arr);
No Bug here. First of all the keys in $arr are 'Test' and 'OtherKey'. In your function you try to access $arr['test'] and $arr['other_key'], which do not exist, hence the notices. Then you unset the key and therefore the result is that $arr is null after the function call, as you passed $arr by reference.

php remove object from array of objects

I'm trying to remove an object from an array of objects by its' index. Here's what I've got so far, but i'm stumped.
$index = 2;
$objectarray = array(
0=>array('label'=>'foo', 'value'=>'n23'),
1=>array('label'=>'bar', 'value'=>'2n13'),
2=>array('label'=>'foobar', 'value'=>'n2314'),
3=>array('label'=>'barfoo', 'value'=>'03n23')
);
//I've tried the following but it removes the entire array.
foreach ($objectarray as $key => $object) {
if ($key == $index) {
array_splice($object, $key, 1);
//unset($object[$key]); also removes entire array.
}
}
Any help would be appreciated.
Updated Solution
array_splice($objectarray, $index, 1); //array_splice accepts 3 parameters
//(array, start, length) removes the given array and then normalizes the index
//OR
unset($objectarray[$index]); //removes the array at given index
$reindex = array_values($objectarray); //normalize index
$objectarray = $reindex; //update variable
array_splice($objectarray, $index, 1);
//array_splice accepts 3 parameters (array, start, length) and removes the given
//array and then normalizes the index
//OR
unset($objectarray[$index]); //removes the array at given index
$reindex = array_values($objectarray); //normalize index
$objectarray = $reindex; //update variable
You have to use the function unset on your array.
So its like that:
<?php
$index = 2;
$objectarray = array(
0 => array('label' => 'foo', 'value' => 'n23'),
1 => array('label' => 'bar', 'value' => '2n13'),
2 => array('label' => 'foobar', 'value' => 'n2314'),
3 => array('label' => 'barfoo', 'value' => '03n23')
);
var_dump($objectarray);
foreach ($objectarray as $key => $object) {
if ($key == $index) {
unset($objectarray[$index]);
}
}
var_dump($objectarray);
?>
Remember, your array will have odd indexes after that and you must (if you want) reindex it.
$foo2 = array_values($objectarray);
in that case you won't need that foreach just unset directly
unset($objectarray[$index]);

Foreach returns only first letter of an array element?

There is almost identical question, but I have no idea what to do in my case.
I'm just starting with OO PHP and I have this function within my class:
public function show() {
foreach($this->data['fields'] as $field) {
$type = $field['type'];
echo $type;
}
}
Here's the input data:
my_function('id',
array(
'foo' => 'bar',
'bar' => 'foo',
'fields' => array(
'type' => 'my_type',
'foo' => 'bar',
'etc.' => 'value'),
),
);
Of course echo $field['type'] returns only the first letter of my_type (m).
And I can't just simply use echo $field as I have multiple keys under this array and it returns my_typebarvalue instead of my_type, the same happens with $field[0] (mbv). What should I do?
There are three key-value pairs in $this->data['fields']: type => my_type, foo => bar and etc. => value. When you use this foreach syntax, $field will contain only the value of the pair, which is always a string.
The index operator (the brackets after the variable, as in $foo['bar']) works on strings as well, and returns the character at the given index. Type juggling turns the string 'type' into the integer 0, and as such you get the first character of the string.
I'm not sure what you want, actually, if echo $field is not okay. PHP will not print newlines or separators unless asked, so you might want to try echo $field . ' ' and see that the values are actually distinct.
When you iterate over fields which is the following:
array(
'type' => 'my_type',
'foo' => 'bar',
'etc.' => 'value'
)
using
foreach($this->data['fields'] as $field)
On each iteration, $field is already the values you are looking for (my_type, bar, value), so doing $field['type'], as #zneak mentioned, will get php to juggle 'type' to 0, hence you get the first character.
To get value when you are at type key, you can do the following:
public function show() {
foreach($this->data['fields'] as $key => $field) {
if($key == 'type') echo $field;
}
}
foreach will iterate over all elements in $data['fields']. On the first iteration, $field will be "my_type", on the second iteration $field will be "bar" and so on. I.e., on each iteration, $field will be a string, not an array.
You will need an array of arrays for that loop to make sense, like:
'fields' => array(
array(
'type' => 'my_type',
'foo' => 'bar',
'etc.' => 'value',
),
...
)
Your array 'fields' is like:
$fields['type'] = 'my_type';
$fields['foo'] = 'bar';
$fields['etc'] = 'value';
Means, that your array has only one dimension.
So access it like above.
In the foreach you tell php to go trough the keys (type, foo, ect). So $field is already (my_type, bar, value)!
// You either need to write:
foreach($this->data as $field) {
$type = $field['fields']['type'];
echo $type;
}
// Or
foreach($this->data['fields'] as $field) {
if ($field == 'type') {
$type = $field;
echo $type;
}
}
// Or
foreach($this->data['fields'] as $key => $val) {
if ($key == 'type') {
$type = $val;
echo $type;
}
}

Categories