PHP associative arrays keys only - php

Is it possible to declare an array element key and not define it a value (like non-array variables)? This way if you have an associative array of booleans, you need only check if the key exists rather than assigning a boolean value. But you'd still have the advantage of not having to iterate over the array when checking if a key exists.
This would be a space saving measure. It appears 'null' gets allocated space.

No. Array element always have key and value, however you may just put anything as your value if you do not care (i.e. empty string). In your case you should just add these keys to your array which are of value i.e. true. And then when you will be looking for it and will be unable to find you can assume it's false. But in general you are doing things wrong. You are NOT really saving here but make your code unclean and hard to read and maintain. Do not do this

If you don't want to have a dictionary structure like in an accoc array, then you just want a set of values, like this:
$array = ('red', 'green', 'blue');
To check if a key (item) exists just use in_array():
if(in_array('red', $array)) {
// -> found
}
However,you should note that php will internally create numeric indicies in this case.
Another way to go would be to assign TRUE to all values. This would at least take less memory. Like this
$array (
'red' => TRUE,
'green' => TRUE,
'blue' => TRUE
);
and check existence using isset() Like:
if(isset($array['red'])) {
// -> found
}
Note: I wouldn't advice you to use NULL as the value. This because you cannot use isset() in this case as isset will return false if the value of a key is NULL. You'll have to use array_key_exists() in this case what is significantly slower than isset().
Conclusion: In terms of processor and memory consumption I would suggest the second advice in PHP. The memory consumption should be the same as with numeric arrays but search operations are optimized.

If i understand correctly.
You plan to use an associative array like this:
key value
"bool1" ""
"bool2" ""
"bool3" ""
And if a key exists, then the bool is "true".
Why not just use an ordinary array like this?:
key value
1 "bool1"
2 "bool2"
3 "bool3"
If the value exists, then the bool is "true".

Yes it's possible. You can also use array_key_exists to check for those values. PHP seperates the hash map of variable names from the actual storage of data (google on zval if you're interested). With that said, arrays pay an additional penalty in having to also have an associated "bucket" structure for each element, that depending on your os and compile options can be as large as 96 bytes/per. Zvals are also as much as 48 bytes each, btw.
I don't think there's any chance you're going to get much value from this scheme however, but purely from a hypothetical standpoint, you can store a null value.
<?php
$foo = array('a' => null, 'b' => null);
if (array_key_exists('a', $foo))
echo 'a';
This does not save you any memory however, if compared to initializing to a boolean. Which would then let you do an isset which is faster than making the function call to array_key_exists.
<?php
$foo = array('a' => true, 'b' => true);
if (isset($foo['a']))
echo 'a';

Related

PHP: What is the real meaning of an index in an indexed array?

Say, we make an array like this:
$arr = Array
(
2 => 'c',
1 => 'b',
0 => 'a'
);
When you pass it to array_pop():
array_pop($arr);
And the "last" element would be poped off, which has the index of zero!!
print_r($arr);
Result:
Array
(
[2] => c
[1] => b
)
So, what's the purpose of index?
Isn't it just a different way of saying "numeric keys of associative arrays"?
Is it only PHP dose so, or all the languages treat arrays like this?
Not all languages do this, but PHP does, because PHP is a little weird. It implements arrays more or less like dictionaries. PHP does offer some functions like ksort though, which let you sort the array by key.
And that's what this is: a key. An array has indexes as well, so what you got, is an array where item 2 has key 0. And that's where the confusion starts continues.
PHP: a fractal of bad design has a whole chapter about arrays. Interesting reading material. :)
The reason for this behavior is because arrays in PHP are actually unordered maps.
Because of this, don't think of accessing the arrays in terms of indexes, think of it in terms of keys. Keys can be numbers and they can be strings, but the result is the same; you're still using a map, not a true "array".
Once you accept that fact, you'll understand why PHP includes functions like ksort() for sorting an array by keys and why array_pop() doesn't always remove the highest key value.
It's a PHP thing. Other languages usually provide other structures to provide what is the default behaviour for arrays on PHP. JavaScript for instance will always sort the array:
a = [];
> []
a[1] = 'a';
> "a"
a[2] = 'b';
> "b"
a[0] = 'c';
> "c"
a
> ["c", "a", "b"]
In Java you would need to use a Hash Map or something else to do Associative Arrays. PHP handles data structures more loosely than other languages.
The index allows you to identify and access the elements of the array.
the reason is simple HashTables.
in php internal functions often use HashTables. basically an array is some data in memory and like in C - an array index can only hold integer values but not in php.
php solves this with hashtables. if you asign a index example foo this value is not directly assigned as foo it gets hashed and maybe end internal as 000000000111 and other hash functions.
so php doesn't work directly with your assigned value and this is the reason why you can set an array index like 0 as last index element. internal php work with hashtables that have a "list" with values which index value is assigned to which position in the array.

How to check an associative array for all null values in php?

This is probably a very trivial question, but please bear with me.
I am trying to read a lot of data into an array of associative arrays. The data contains a lot of empty arrays and arrays with keys set and but all null values. I want to ignore those and only push arrays with at least one key mapped to a non-null value. (The data comes from an excel sheet and it has lots of empty cells that are registered as "set" anyway.) So far I have tried:
if(!empty(${$small_dummy}))
array_push(${$big_dummy}, ${$small_dummy});
That gets rid of the empty arrays but not the ones where all keys map to null. Is there a better way to do this than looping through the entire array and popping all null values?
Judging by the code you have already, you can change:
if(!empty(${$small_dummy}))
to:
if(!empty(array_filter(${$small_dummy})))
That will filter out all empty values (values evaluating to FALSE to be precise) and check if the resulting array is empty. Also see the manual on array_filter().
Note that this would also filter 0 values so you might need to write a custom callback function for array_filter().
You can try if(!array_filter($array)) { also
This isn't an ideal approach, but array_sum will return 0 if all values can't be cast to a numeric value. So :
$small_dummy = array("a" => null, "foo", "", 0);
if(array_sum($small_dummy) === 0)
would pass. But this is only the way to go if you are expecting the values to be numeric.
Actually, if the problem is that the array keys have values and therefor are not passing as empty(), the go with array_values:
if(!empty(array_values(${$small_dummy})))

PHP array comparison algorithm

While trying to simulate a bit of PHP behaviour I stumbled across this:
$a=array(0 => 1, 'test' => 2);
$b=array('test' => 3, 0 => 1);
var_dump($a==$b, $a>$b, $b>$a);
According to the output from var_dump $b is bigger than $a. In the PHP manual there is a Transcription of standard array comparison which states that the values of the arrays are compared one by one and if a key from the first array is missing in the second array, the arrays are uncomparable. So far so good. But if I try this (change in the first element of $a only):
$a=array(0 => 2, 'test' => 2);
$b=array('test' => 3, 0 => 1);
var_dump($a==$b, $a>$b, $b>$a);
All three comparison results are false. This looks like "uncomparable" to me (because the > result is the same as the < result, while the arrays are not ==either, which makes no sense) but this does not fit the transcription from the PHP manual. Both keys are present in both arrays and I would expect $a to be bigger this time because the content of key 0 is bigger in $a (2 vs. 1).
I've tried to dig into the PHP source code and found zend_hash_compare() in zend_hash.c, but the code there seems to work as the manual describes.
What's going on here?
EDIT: As Joachim has shown, it deals with the order called. To steal his words:
"$a>$b loops over b and finds 'test' first. 'test' is greater in $b so $b is greater and it returns false. $b>$a loops over a and finds '0' first. '0' is greater in $a so $a is greater and it returns false."
-- Original Post --
I'm not 100% sure I'm right on this; I haven't seen this before, and have only briefly looked into it (major kudos, by the way, on an excellent question!). Anyway, it would appear that either PHP documentation is wrong, or this is a bug (in which case you might want to submit it), and here is why:
in zend_hash_compare() in zend_hash.c, it seems as though there is some confusion over what ordered is (I'm looking at line 1514 and 1552-1561, which is my best guess is where the problem is, without doing lots of testing).
Here's what I mean; try this:
$a=array(0 => 2, 'test' => 2);
$b=array(0 => 1, 'test' => 3);
var_dump($a==$b, $a>$b, $b>$a);
Note I merely switched the order of indexes, and $a>$b returns true. Also see this:
$x=array(0 => 2, 'test' => 2);
$y = $x;
$y[0] = 1; $y['test'] = 3;
var_dump($x==$y, $x>$y, $y>$x);
Note here, as well, $x>$y returns true. In other words, PHP is not just matching array keys! It cares about the order of those keys in the arrays! You can prevent this situation by coming up with a "base" array and "copying" it into new variables (in my x/y example) before modifying, or you can create an object, if you so desire.
To say all that differently, and much more briefly, it would appear that PHP is not just looking at key values, but at both key values AND key order.
Again, I emphasize I don't know if this expected behavior (it seems like something they ought to have noted in the PHP manual if it was), or a bug/error/etc (which seems much more likely to me). But either way, I'm finding that it is compared first by number of keys (lines 1496-1501 in zend_hash.c), and then by both key value and key order.
It would seem that the comparison loop is in the case of > done over the right hand array and in the case of < done over the left hand array, ie always over the supposedly "lesser" array. The order of the elements is significant as the foreach loop in the transcription code respects array order.
In other words;
$a>$b loops over b and finds 'test' first. 'test' is greater in $b so $b is greater and it returns false.
$b>$a loops over a and finds '0' first. '0' is greater in $a so $a is greater and it returns false.
This would actually make sense, the "greater" array is then allowed to contain elements that the "lesser" array doesn't and still be greater as long as all common elements are greater.
I think here is comparing one by one so $a[0]>$b[0] but $a['test']<$b['test'].
You can not say which array is bigger.

php associative array values always set?

$test['test'] = 'test';
if(isset($test['test']['x']))
return $test['test']['x'];
This statement returns the first character of the string in $test['test'] (in this case 't'), no matter what is specified as dimension 2.
I can't wrap my head around this behavior. I use isset() all the time. Please advise.
This happens because you're not indexing an array, you're indexing a string. Strings are not arrays in PHP. They happen to share a concept of indexes with arrays, but are really character sequences even though there is no distinct char data type in PHP.
In this case, since strings are only indexed numerically, 'x' is being converted into an integer, which results in 0. So PHP is looking for $test['test'][0]. Additionally $test is only a single-dimensional array, assuming 'test' is the only key inside.
Not really relevant to your question, but if you try something like this you should get 'e', because when converting '1x' to an integer, PHP drops anything that isn't a digit and everything after it:
// This actually returns $test['test'][1]
return $test['test']['1x'];
If you're looking for a second dimension of the $test array, $test['test'] itself needs to be an array. This will work as expected:
$test['test'] = array('x' => 'test');
if (isset($test['test']['x']))
return $test['test']['x'];
Of course, if your array potentially contains NULL values, or you want to make sure you're checking an array, use array_key_exists() instead of isset() as sirlancelot suggests. It's sliiiiightly slower, but doesn't trip on NULL values or other indexable types such as strings and objects.
Use array_key_exists for testing array keys.
It's returning 't' because all strings can be treated as arrays and 'x' will evaluate to 0 which is the first letter/value in the variable.

How to check if an array has an element at the specified index?

I know there is array_key_exists() but after reading the documentation I'm not really sure if it fits for this case:
I have an $array and an $index. Now I want to access the $array, but don't know if it has an index matching $index. I'm not talking about an associative array, but an plain boring normal numerically indexed array.
Is there an safe way to figure out if I would really access an $array element with the given $index (which is an integer!)?
PHP may not care if I access an array with an index out of bounds and maybe just returns NULL or so, but I don't want to even attempt to code dirty, so I want to check if the array has the key, or not ;-)
You can use either the language construct isset, or the function array_key_exists : numeric or string key doesn't matter : it's still an associative array, for PHP.
isset should be a bit faster (as it's not a function), but will return false if the element exists and has the value NULL.
For example, considering this array :
$a = array(
123 => 'glop',
456 => null,
);
And those three tests, relying on isset :
var_dump(isset($a[123]));
var_dump(isset($a[456]));
var_dump(isset($a[789]));
You'll get this kind of output :
boolean true
boolean false
boolean false
Because :
in the first case, the element exists, and is not null
in the second, the element exists, but is null
and, in the third, the element doesn't exist
On the other hand, using array_key_exists like in this portion of code :
var_dump(array_key_exists(123, $a));
var_dump(array_key_exists(456, $a));
var_dump(array_key_exists(789, $a));
You'll get this output :
boolean true
boolean true
boolean false
Because :
in the two first cases, the element exists -- even if it's null in the second case
and, in the third, it doesn't exist.
You can easily use isset():
if (isset($array[$index])) {
// array index $index exists
}
And as you have suggested, PHP is not very kind if you try to access a non-existent index, so it is crucial that you check that you are within bounds when dealing with accessing specific array indexes.
If you decide to use array_key_exists(), please note that there is a subtle difference:
isset() does not return TRUE for array
keys that correspond to a NULL value,
while array_key_exists() does.
That's exactly what the array_key_exists is for. It works on both numerical and string indexes.

Categories