I have a function that returns an array, and is passed to foreach i.e.
foreach(function() as $val)
Since the array I am returning is declared in a series of if statements, I need to return an empty array if all the if statements are evaluated to false. Is this a correct way to do it?
if (isset($arr))
return $arr;
else
return array();
I would recommend declaring $arr = array(); at the very top of the function so you don't have to worry about it.
If you are doing the check immediately before you return, I do not recommend isset. The way you are using foreach is depending on an array being returned. If $arr is set to a number, for example, then it will still validate. You should also check is_array(). For example:
if (isset($arr) && is_array($arr))
return $arr;
else
return array();
Or in one line instead:
return (isset($arr) && is_array($arr)) ? $arr : array();
But, like I said, I recommending declaring the array at the very top instead. It's easier and you won't have to worry about it.
To avoid complexity, Simply
return [];
Related
I have an array that I want to test for empty elements, I have tried using array_walk to walk an array (a single dimension array) and return true if the array of elements (values) has got any empty elements.
I naturally went to the PHP website, looked at the examples on offer and they don't make any sense because it does not give a clear example of how you would use array_walk for this. I tried array_filter and that didn't seem to do much either.
Example of what I was trying to do.
$test = array("Tree"=>"Ash","TreeID"=>"Q23-123","count"=>14,"User"=>"P.Williams");
$result = array_walk( $test, "empty", true );
All I get as a result is "Array".
and PHP parser is having a hissy fit about it, they say clearly, bool array_walk ( array &$array , callable $callback [, mixed $userdata = NULL ] ) in their site, this I deduced to be something $result array_walk ( $theTargetArray, "StringNameOfFunction", theResultIfTure); but nothing is that simple.
So far I have found lots of examples on many sites and it seems that people have just copied and pasted the PHP examples, some have changed their names to hide that they have copied and pasted the example...
Can someone let me know what it is that I am doing wrong here please?
(Also FAO stackoverflow site maintainers, What is the point in suggesting a tag, I click to use it and then I get told I can not create a new tag unless I have 1500 points??? Seriously Why? Good idea if you go and think about that one.)
$my_arr = array(....); // your array here
$has_empty_value = sizeof($my_arr) != sizeof(array_filter($my_arr));
array_walk is not going to help you on that. It's a mutator function, and is intended to change array elements, not to retrieve information about them. What you're looking for is a boolean aggregator function known as any or some in other languages. PHP doesn't provide it out of the box, so you have to write it by hand:
function any($iter, $pred) {
foreach($iter as $item)
if($pred($item))
return true;
return false;
}
However, an attempt to use it with empty, as in
print any($test, 'empty')
will fail, because empty is not a real function and can't be used indirectly. A workaround is to wrap it in yet another function and pass that one to any:
any($test, function($x) { return empty($x); })
Another option is to filter an array through boolval, thus removing "falsy" values, and compare lengths:
$hasEmptyElements = count(array_filter($test, 'boolval')) < count($test);
Note that, unlike any, which is "lazy", filter always processes the whole array.
The docs for array_walk say "Applies the user-defined callback function to each element of the array array." Therefore, you can use it with your own callbacks or with with a closure, like so:
$test = array("Tree"=>"Ash","TreeID"=>"Q23-123", "count"=> 14, "User"=>"P.Williams");
$result = array_walk( $test, function($value) {
return empty($value);
});
Of course, this depends on what you are trying to achieve as this will loop through all the values and $result will be true if all the values are empty but the last one is not.
If you are looking to find out if any of the values are empty, a function that stops after it finds an empty item would be better:
function hasEmptyValues(array $array)
{
foreach ($array as $key => $value) {
if (empty($value)) {
//Empty value found
return true;
}
}
//None of the values are empty
return false;
}
I got some trouble with in_array()
$list = array(
"files/" => "/system/application/files/_index.php",
"misc/chat/" => "/system/application/misc/chat/_index.php"
);
I have this $_GET['f'] which holds the string files/.
How can I search through the array for possible matches?
If the string is found in the array, then the file should be included
Thanks for any help :)
It's really simple. All you need to do is check if the array element is set. The language construct that's usually used is isset() (yes, it's that obvious)...
if (isset($list[$_GET['f']])) {
}
There's no need to call a function for this, isset is cleaner and easier to read (IMHO)...
Note that isset is not actually a function. It's a language construct. That has a few implications:
You can't use isset on the return from a function (isset(foo()) won't work). It will only work on a variable (or a composition of variables such as array accessing or object accessing).
It doesn't have the overhead of a function call, so it's always fast. The overall overhead of a function call is a micro-optimization to worry about, but it's worth mentioning if you're in a tight loop, it can add up.
You can't call isset as a variable function. This won't work:
$func = 'isset';
$func($var);
array_key_exists is a function that returns true of the supplied key is in the array.
if(array_key_exists( $_GET['f'], $list )) {
echo $list[$_GET['f']];
}
You can use in_array() in conjunction with array_keys():
if (in_array($_GET['f'], array_keys($list))) {
// it's in the array
}
array_keys() returns an array of the keys from its input array. Using $list as input, it would produce:
array("files/", "misc/chat/");
Then you use in_array() to search the output from array_keys().
Use array_key_exists.
if(array_key_exists($_GET['f'], $list)){
// Do something with $list[$_GET['f']];
}
in_array() searches array for key using loose comparison unless strict is set.
it's like below.
foreach ($array as $value){
if ($key == $value){
return true;
}
}
My way.
function include_in_array($key, $array)
{
foreach($array as $value){
if ( strpos($value, $key) !== false ){
return false;
}
}
}
I have an array with numerous dimensions, and I want to test for the existence of a cell.
The below cascaded approach, will be for sure a safe way to do it:
if (array_key_exists($arr, 'dim1Key'))
if (array_key_exists($arr['dim1Key'], 'dim2Key'))
if (array_key_exists($arr['dim1Key']['dim2Key'], 'dim3Key'))
echo "cell exists";
But is there a simpler way?
I'll go into more details about this:
Can I perform this check in one single statement?
Do I have to use array_key_exist or can I use something like isset? When do I use each and why?
isset() is the cannonical method of testing, even for multidimensional arrays. Unless you need to know exactly which dimension is missing, then something like
isset($arr[1][2][3])
is perfectly acceptable, even if the [1] and [2] elements aren't there (3 can't exist unless 1 and 2 are there).
However, if you have
$arr['a'] = null;
then
isset($arr['a']); // false
array_key_exists('a', $arr); // true
comment followup:
Maybe this analogy will help. Think of a PHP variable (an actual variable, an array element, etc...) as a cardboard box:
isset() looks inside the box and figures out if the box's contents can be typecast to something that's "not null". It doesn't care if the box exists or not - it only cares about the box's contents. If the box doesn't exist, then it obviously can't contain anything.
array_key_exists() checks if the box itself exists or not. The contents of the box are irrelevant, it's checking for traces of cardboard.
I was having the same problem, except i needed it for some Drupal stuff. I also needed to check if objects contained items as well as arrays. Here's the code I made, its a recursive search that looks to see if objects contain the value as well as arrays. Thought someone might find it useful.
function recursiveIsset($variable, $checkArray, $i=0) {
$new_var = null;
if(is_array($variable) && array_key_exists($checkArray[$i], $variable))
$new_var = $variable[$checkArray[$i]];
else if(is_object($variable) && array_key_exists($checkArray[$i], $variable))
$new_var = $variable->$checkArray[$i];
if(!isset($new_var))
return false;
else if(count($checkArray) > $i + 1)
return recursiveIsset($new_var, $checkArray, $i+1);
else
return $new_var;
}
Use: For instance
recursiveIsset($variables, array('content', 'body', '#object', 'body', 'und'))
In my case in drupal this ment for me that the following variable existed
$variables['content']['body']['#object']->body['und']
due note that just because '#object' is called object does not mean that it is. My recursive search also would return true if this location existed
$variables->content->body['#object']->body['und']
For a fast one liner you can use has method from this array library:
Arr::has('dim1Key.dim2Key.dim3Key')
Big benefit is that you can use dot notation to specify array keys which makes things simpler and more elegant.
Also, this method will work as expected for null value because it internally uses array_key_exists.
If you want to check $arr['dim1Key']['dim2Key']['dim3Key'], to be safe you need to check if all arrays exist before dim3Key. Then you can use array_key_exists.
So yes, there is a simpler way using one single if statement like the following:
if (isset($arr['dim1Key']['dim2Key']) &&
array_key_exists('dim3Key', $arr['dim1Key']['dim2Key'])) ...
I prefer creating a helper function like the following:
function my_isset_multi( $arr,$keys ){
foreach( $keys as $key ){
if( !isset( $arr[$key] ) ){
return false;
}
$arr = $arr[$key];
}
return $arr;
}
Then in my code, I first check the array using the function above, and if it doesn't return false, it will return the array itself.
Imagine you have this kind of array:
$arr = array( 'sample-1' => 'value-1','sample-2' => 'value-2','sample-3' => 'value-3' );
You can write something like this:
$arr = my_isset_multi( $arr,array( 'sample-1','sample-2','sample-3' ) );
if( $arr ){
//You can use the variable $arr without problems
}
The function my_isset_multi will check for every level of the array, and if a key is not set, it will return false.
This question already has answers here:
Invalid argument supplied for foreach()
(20 answers)
Closed 7 years ago.
Not a major problem but I was wondering if there is a cleaner way to do this. It would be good to avoid nesting my code with an unnecessary if statement. If $items is empty php throws an error.
$items = array('a','b','c');
if(!empty($items)) { // <-Remove this if statement
foreach($items as $item) {
print $item;
}
}
I could probably just use the '#' error suppressor, but that would be a bit hacky.
There are a million ways to do this.
The first one would be to go ahead and run the array through foreach anyway, assuming you do have an array.
In other cases this is what you might need:
foreach ((array) $items as $item) {
print $item;
}
Note: to all the people complaining about typecast, please note that the OP asked cleanest way to skip a foreach if array is empty (emphasis is mine). A value of true, false, numbers or strings is not considered empty.
In addition, this would work with objects implementing \Traversable, whereas is_array wouldn't work.
The best way is to initialize every bloody variable before use.
It will not only solve this silly "problem" but also save you a ton of real headaches.
So, introducing $items as $items = array(); is what you really wanted.
$items = array('a','b','c');
if(is_array($items)) {
foreach($items as $item) {
print $item;
}
}
If variable you need could be boolean false - eg. when no records are returned from database or array - when records are returned, you can do following:
foreach (($result ? $result : array()) as $item)
echo $item;
Approach with cast((Array)$result) produces an array of count 1 when variable is boolean false which isn't what you probably want.
I wouldn't recommend suppressing the warning output. I would, however, recommend using is_array instead of !empty. If $items happens to be a nonzero scalar, then the foreach will still error out if you use !empty.
I think the best approach here is to plan your code so that $items is always an array. The easiest solution is to initialize it at the top of your code with $items=array(). This way it will represent empty array even if you don't assign any value to it.
All other solutions are quite dirty hacks to me.
foreach((array)$items as $item) {}
i've got the following function in my "standard library"
/// Convert argument to an array.
function a($a = null) {
if(is_null($a))
return array();
if(is_array($a))
return $a;
if(is_object($a))
return (array) $a;
return $_ = func_get_args();
}
Basically, this does nothing with arrays/objects and convert other types to arrays. This is extremely handy to use with foreach statements and array functions
foreach(a($whatever) as $item)....
$foo = array_map(a($array_or_string)....
etc
Ternary logic gets it down to one line with no errors. This solves the issue of improperly cast variables and undefined variables.
foreach (is_array($Items) || is_object($Items) ? $Items : array() as $Item) {
It is a bit of a pain to write, but is the safest way to handle it.
You can check whether $items is actually an array and whether it contains any items:
if(is_array($items) && count($items) > 0)
{
foreach($items as $item) { }
}
Best practice is to define variable as an array at the very top of your code.
foreach((array)$myArr as $oneItem) { .. }
will also work but you will duplicate this (array) conversion everytime you need to loop through the array.
since it's important not to duplicate even a word of your code, you do better to define it as an empty array at top.
I'd like to check if there is a value on an array like this:
function check_value_new ($list, $message) {
foreach ($list as $current) {
if ($current == $message) return true;
}
return false;
}
function check_value_old ($list, $message) {
for ($i = 0; $i < count ($status_list); $i ++) {
if ($status_list[$i] == $$message) return true;
}
return false;
}
$arr = array ("hello", "good bye", "ciao", "buenas dias", "bon jour");
check_value_old ($arr, "buenas dias"); // works but it isn't the best
check_value_new ($arr, "buenas dias"); // argument error, where I'm wrong?
I've read the check_value_new method is a better way to work with arrays, but I'm not used to work with it, how I should fix it?
PHP offers a function called in_array that checks if a value exists in a given array.
You can change your check_value_new function to include this:
function check_value_new ($list, $message) {
foreach ($list as $current) {
if (in_array($message, $current)) {
return true;
}
return false;
}
If you'd like to, you could also make the function work without the foreach loop, like so
function check_value_new ($list, $message) {
// returns true if found, else returns false.
return in_array($message, $list);
}
The reasons that your check_value_old() function breaks is because you have a typo in your loop's second parameter. $status_list is not one of the variables passed into your function and it is not declared anywhere before it is used. You merely need to use $list instead. It is also not necessary to call count() on every iteration -- since that value never changes in the loop, just call it once before the loop and use that value in the second parameter.
As for deciding how to loop over array values, there is no reason to reinvent a native function call. in_array() was already designed and optimized to search linear values in an array and return true as soon as it finds a match; otherwise it returns false.
I don't know what #AnthonyForloney is doing by writing in_array() inside of a foreach() loop. Not only will the snippet break because there aren't enough curly braces, the input array does not have two levels of data, so in_array() will choke when it receives $current which is a string (not the expected array).
Ultimately, my advice is: Only write your own custom function when there isn't a native function to suit your needs. Throw away both of the manual looping ideas and only call:
$arr = ["hello", "good bye", "ciao", "buenas dias", "bon jour"];
var_export(in_array("buenas dias", $arr));
One final insight that I'd like to provide is regarding microoptimization. If you are planning to check the existence of a unique value in a "very large" array, or if you are going to be making thousands of searches on the same array, then it would be more efficient to set up your array in a "flipped" orientation and call isset() or array_key_exists(). isset()/array_key_exists() will always outperform in_array() or array_search() because of the way that php handles arrays as "hash maps". More reading here.