passing null as array_keys second parameter - php

PHP documentation states that the default value of array_keys second argument is NULL.
However, when passing NULL explicitly, array_keys does not seem to work properly.
Example:
code
$a = array(10=>'a', 11=>'b', 12=>'b', 13=>'c', 14=>'c', 15=>'b');
$keys = array_keys($a);
var_dump($keys); //Output 0
$keys = array_keys($a, null);
var_dump($keys); //Output 1
Output
array
0 => int 10
1 => int 11
2 => int 12
3 => int 13
4 => int 14
5 => int 15
array
empty
Question
I reckon it must be trying to find keys whose value is null.
Passing false or empty string produces the exact same behavior (obviously).
So, what is the default value?
Answer
xdazz answer is right. When inspecting the C code of this function, my first though was that this was a bad implementation at C level (and easily fixed by removing code)
But then I realized this is actually the intended behavior since they went to a lot of trouble to enable you to test for NULL values inside the array.

The default value is hard to explain here.
It is special case, the default value of second parameter is not actually the php's NULL, but the C level's NULL.
Dive into the source code:
PHP_FUNCTION(array_keys)
{
zval *input, /* Input array */
*search_value = NULL, /* Value to search for */
//....
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zb", &input, &search_value, &strict) == FAILURE) {
return;
}
// ....
You could see, the default value is NULL for search_value, but if you specified the second parameter of array_keys, then after zend_parse_parameters, search_value will not be NULL.

I agree with xdazz. However, it seems that passing 0 works. Don't ask me how, though! (And, YMMV.)
$a = array(10=>'a', 'xaa'=>'b', 12=>'b', 13=>'c', 14=>'c', 15=>'b');
$keys = array_keys($a, 0);
var_dump($keys); //Output 0
Returns:
array(6) { [0]=> int(10) [1]=> string(3) "xaa" [2]=> int(12) [3]=> int(13) [4]=> int(14) [5]=> int(15) }

Since you're searching for null, there's no result to give back to you :)

It is hard to infer from PHP manual as to the use of search_value parameter. I needed to do try an example.
If the optional search_value is specified,
then only the keys for **that** value are returned.
Otherwise, all the keys from the input are returned.
It means that when search_value is specified in array_keys(), the values in the array (not keys) are searched against search_value. If match occurs, the key for that value in search_value is returned.
Example
<?
$foo = array('first' => 'my_first',
'second' => 'my_second',
'third' => 'my_third',
'fourth' => null);
$keys = array_keys($foo);
var_dump($keys); //Output 0
$keys = array_keys($foo, 'my_second');
var_dump($keys); //Output 1
$keys = array_keys($foo, null);
var_dump($keys); //Output 2
?>
Output
0:
array(4) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
[2]=>
string(5) "third"
[3]=>
string(6) "fourth"
}
1:
array(1) {
[0]=>
string(6) "second"
}
2:
array(1) {
[0]=>
string(6) "fourth"
}

Related

Search for array row with specific column value and return another value from qualifying row

I have a multidimensional array that I am trying to search for a specific value (url) and then retrieve an another value in the same row (value). I also need to divert to an else if it is not found.
array(2) {
[0]=> array(2) {
["url"]=> string(7) "fareham"
["value"]=> string(7) "Fareham"
}
[1]=> array(2) {
["url"]=> string(11) "southampton"
["value"]=> string(11) "Southampton"
}
}
I have been experimenting with array_key_exists() and isset() to check it's set and just coming up null!
For example, if I search for fareham, I want to return Fareham. If I search for nottingham, I expect null.
How can I isolate the qualifying value?
Use array_column() to index the data by the url columns and then use isset() to check if the value is there...
$data = array_column($data, "value", "url");
$search = 'southampton';
$value = isset($data[$search])?$data[$search]:"not found";
echo $value;
or for PHP 7+, you can use the null coalescing operator (??)
$value = $data[$search]??"not found";
Here is the minimal way to do it (no checks)
$a = array (
0 =>
array (
"url" => 'fareham',
"value" => 'Fareham'
),
1 =>
array (
"url" => 'southampton',
"value" => 'Southampton'
)
);
$u = 'fareham';
$i = $a[false===($f=array_search($u,array_column($a,'url')))?-1:$f]['value'];
print_r($i);
Output
Fareham
Sandbox
How it works
First we create an array we can search by using array_column on the column we want to search in this case url. It looks like this [0=>'fareham', 1=>'southampton']
Then we use the normal array_search which returns an index, if you notice above the indexes are correlated to the original array. Which means we can put that in as the top level key, then it's a simple matter of adding the key we want.
Because array_search can return a boolean(false) which PHP sees as 0 or the first index I put a little hack in for that. But a better way is to check it like this:
$a = array (
0 =>
array (
"url" => 'fareham',
"value" => 'Fareham',
"extra" => 'Foo'
),
1 =>
array (
"url" => 'southampton',
"value" => 'Southampton',
"extra" => 'Bar'
)
);
function serchMultiDimensionalValue($needle, $haystack, $fields='value'){
if(false === ($f=array_search($needle,array_column($haystack,'url')))) return false; //or return [];
if(!is_array($fields)) $fields = [$fields];
return array_intersect_key($haystack[$f], array_flip($fields));
}
var_dump(serchMultiDimensionalValue('foo',$a));
var_dump(serchMultiDimensionalValue('fareham',$a));
var_dump(serchMultiDimensionalValue('fareham',$a, 'extra'));
var_dump(serchMultiDimensionalValue('fareham',$a, ['extra','url']));
Ouput
bool(false)
array(1) {
["value"]=>
string(7) "Fareham"
}
array(1) {
["extra"]=>
string(3) "Foo"
}
array(2) {
["url"]=>
string(7) "fareham"
["extra"]=>
string(3) "Foo"
}
Sandbox
I added a bit more "functionality" to it, hope you don't mind.
While it might be alluring to seek out a one-liner like:
array_column($array, $returnColumn, $haystackColumn)[$needle] ?? null
Be aware that array_column() will be unconditionally doubling the memory usage (because it is generating a new array with the same length as the original) for the sake of assigning new first level keys to search by.
Metaphorically speaking, it is like building a new registry of residences in a neighborhood including every homeowner's name and their address. Yes, you can find out who lives at a given home without knocking on the front door, but you had to knock on every door to collect every home's details before enjoying this convenience. Why not just knock on the door of each original house and ask if they are who you are looking for? It is much easier, and you will be able to "quit" early as soon as you find the homeowner that you are looking for.
For best efficiency and for least memory usage, I recommend the below classic loop with conditional break. It is built with dynamic search and return variables for general usage, but you can use hardcoded values if you like.
Code: (Demo)
$array = [
["url" => 'fareham', "value" => 'Fareham'],
["url" => 'southampton', "value" => 'Southampton']
];
$needle = 'fareham';
$haystackColumn = 'url';
$returnColumn = 'value';
$value = null;
foreach ($array as $row) {
if ($row[$haystackColumn] === $needle) {
$value = $row[$returnColumn];
break;
}
}
var_export($value); // 'Fareham'

Understanding PHP arrays, specifically example given

I am new to PHP and arrays and am wanting to understand the following array. I would also like to learn how I would go about assigning values to two particular array elements in PHP, i.e.:
["_gravity_form_lead"]=> array(5) { [1]=> string(4) "1000" [3]=> string(6) "strips" [2]=> string(2) "rp" [5]=> string(0) "" [6]=> string(0) "" }
1) What is the correct notation to define this array?
2) For the two array elements that are "", i.e.
[5]=> string(0) "" [6]=> string(0) ""
In PHP, how would I go about assigning values to these two array elements, that are NULL?
Hope this makes you understand ,
$array_before = array('_gravity_form_lead' => array( '1000', "strips", "rp", '', ''));
echo '<pre>';
echo 'This what it looks after print_r'.'<br>';
print_r($array_before);
echo '</pre>';
I don't see anything different and special than its said in the documentation
http://php.net/manual/en/language.types.array.php
Anyway, the concrete situation is.
$_gravity_form_lead = array(1=>1000, 3=>'strips', 2=>'rp', 5=>'', 6=>'');
As said in the documentation
Creating/modifying with square bracket syntax ΒΆ
An existing array can be modified by explicitly setting values in it.
This is done by assigning values to the array, specifying the key in brackets. The key can also be omitted, resulting in an empty pair of brackets ([]).
$arr[key] = value;
You do modify the ones you need with [ ]
In this particular case:
$_gravity_form_lead[5] = 'something';
$_gravity_form_lead[6] = 'something else';
In order you want to modify all empty strings, you can iterate through the array and modify. You have two options while iterating - using reference &, which will modify the existent one, or creating new array.
foreach ($_gravity_form_lead as &$val) {
if ($val == '') {
$val = 'something';
}
}
The output after doing this is
var_dump($_gravity_form_lead);
/*
* array (size=5)
1 => int 1000
3 => string 'strips' (length=6)
2 => string 'rp' (length=2)
5 => string 'something' (length=9)
6 => &string 'something' (length=9)
*/
It would be defined somewhat like,
$arrayName = array('_gravity_form_lead' => array( 1=>'1000', 3=>"strips", 2=>"rp", 5=>'', 6=>''));
/* assign null instead of '' */
$arrayName['_gravity_form_lead'][5] = NULL;
$arrayName['_gravity_form_lead'][6] = NULL;

Associative Array Key Casting Float String

In my code, I have generated an associative array with keys as floats, however the PHP documentation states that when they become key's in the array they are SUPPOSED to be cast to integers. Instead, they are being cast to strings (which is actually better for me so I'm not complaining).
The problem is that when I try to access these keys using a float as the key value, it casts only the floats with .5 to integers and creates a new entry in the array. Seems like peculiar behavior.
Example:
var_dump( $array );
Output:
array(9) {
[0] =>
int(0)
[1.25] =>
int(0)
[2.5] =>
int(0)
....}
When I try to access the value 2.5 like so,
array[2.5]++;
a new entry in the array is made at array[2]
However if I try to access the array at array[1.25]++;
I successfully add 1 to the value at key: 1.25
Any ideas?
I would just stick with strings all the time:
$a = array(
'0' => 0,
'1.25' => 0,
'2.5' => 0
);
$a['2.5']++;
echo $a['2.5'] . "\n";
var_dump($a);
Output is:
1
array(3) {
[0]=>
int(0)
["1.25"]=>
int(0)
["2.5"]=>
int(1)
}

array_merge strange behaviour

Look at this code:
$a = array('1'=>'1');
$b = array(''=>'');
var_dump(array_merge($a,$b));
the output seems really strange to me:
array(2) {
[0] =>
string(1) "1"
'' =>
string(0) ""
}
Ok, I've changed $a into this: $a = array('k'=>'v'); and the output became more predictable:
array(2) {
'k' =>
string(1) "v"
'' =>
string(0) ""
}
The question is: why the hell the key of the first element is 0 in the first example?
edit:
var_dump($a);
array(1) {
[1] =>
string(1) "1"
}
Values in the input array with numeric keys will be renumbered with incrementing keys starting from zero in the result array.
http://php.net/array_merge
Yes, it's an idiosyncrasy of PHP to treat numeric string values as numeric values in this case. You may want to use $a + $b instead.

How to get keys/values from an incomplete associative array?

I have this kind of array:
$a = array(
'one' => 'one',
'0' => '0',
'two' => 'two',
'three' => 'three',
'four'
);
as you can see it is an associative array BUT not all the keys have the value (take a look at the last).
My question is, how can i loop this kind of array to get key(if exists) and the respective value?
Thank you!
The string 'four' in your example is not a key but a value. The corresponding key will be 1. This happens because PHP converts the string key '0' to numeric key 0 and for the value 'four' it uses the next numeric key which will be 1.
Reference:
A key may be either an integer or a string. If a key is the standard
representation of an integer, it will be interpreted as such (i.e. "8"
will be interpreted as 8, while "08" will be interpreted as "08")
To have a key with no value you can use NULL as the value:
'four' => null
Similarly to have an empty key use null as key:
null => 'four'
And to loop over such an array you can use a foreach loop. To detect if a key/value is null or not you can use the isset function.
With var_dump($a); you see all keys and values:
array(5) {
["one"] => string(3) "one"
[0] => string(1) "0"
["two"] => string(3) "two"
["three"] => string(5) "three"
[1] => string(4) "four"
}
you can use the foreach construction:
foreach($a as $key=>$val){
// $key is a current key
// $val is tha current value associated
}
As described in PHP: Arrays
A key may be either an integer or a string. If a key is the standard representation of an integer, it will be interpreted as such (i.e. "8" will be interpreted as 8, while "08" will be interpreted as "08"). Floats in key are truncated to integer. The indexed and associative array types are the same type in PHP, which can both contain integer and string indices.
So you cannot distinguish key '0' and 0. And your last element is not a key, it is a value with auto incremental integer key 1. You can check with var_dump($a):
array(5) {
["one"]=>
string(3) "one"
[0]=>
string(1) "0"
["two"]=>
string(3) "two"
["three"]=>
string(5) "three"
[1]=>
string(4) "four"
}
If you can ensure all your keys do not start with digit, then you can just iterate the array as usual, and test the key using is_int.

Categories