$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.
Related
I was working on a project at my job and came upon this code:
$queryStringValue = $_GET['var'];
if ( is_string($queryStringValue) )
{
// Do something.
}
My question: Is calling is_string() to check if the query string value is a string completely unnecessary? By definition, "query string" leads me to believe the data type can only be a string, thus making a call to is_string() redundant.
Am I right, or are there times when a different data type can be passed in a query string?
Thank you for any insight!
Per PHP manual on Variables From External Sources under "Determining variable types":
HTTP being a text protocol, most, if not all, content that comes in Superglobal arrays, like $_POST and $_GET will remain as strings. PHP will not try to convert values to a specific type.
Again, in the manual's FAQ: Arrays in HTML Form, we read on arrays:
To get your <form> result sent as an array to your PHP script you name the <input>, <select> or <textarea> elements like this:
<input name="MyArray[]" /> ...
This would turn into a query string ?MyArray[]=foo&MyArray[]=bar etc., available as $_GET['MyArray'][0] and $_GET['MyArray'][1]. You can also use named keys; the query ?var[x]=one&var[y]=two would result in the associative array $_GET['var] = ['x' => 'one', 'y' => 'two']; and ?var[x][]=deep would become $_GET['var']['x'] = ['deep'], etc.
In addition, the manual for $_GET notes the following:
Note:
The GET variables are passed through urldecode().
Then, see the signature of urldecode:
urldecode ( string $str ) : string
In other words, the function used for preprocessing $_GET values accepts a string and returns a string. Evidently, when there's an array incoming, it will apply urldecode to each string value of that array instead. (If someone cares to find the PHP source code section responsible for generating $_GET, please share the link, will include it here.)
Note that an empty value, e.g. in ?foo&bar=1, will not result in [foo] NULL, but rather in [foo] string(0) "", in other words a zero-length string. Again, we get [bar] string(1) "1". There's no type-casting of get or post values into integers, floats, booleans or null.
In conclusion, the possible datatypes received in $_GET are string and array (of strings; or further arrays; with the final, scalar "leaves" being strings). Of course, if you explicitly declare $_GET['foo'] = null or $_GET['bar'] = 1 in your PHP code, then there will be integers and nulls. The above applies to variables parsed by PHP from external sources.
Update: While the above is true for all the values parsed from the query string, things are different for the keys PHP extracts from a query string. Suppose the following URL:
test.php?101=foo&202=bar&dev=ops
Now, what will var_dump(array_keys($_GET)) return for the numeric keys? Integers, not strings:
array(3) {
[0] · int(101)
[1] · int(202)
[2] · string(3) "dev"
}
This is in line with PHP's standard casting of array keys: "Strings containing valid decimal integers, unless the number is preceded by a + sign, will be cast to the integer type.". The following key cast will however not happen: "Floats are also cast to integers, which means that the fractional part will be truncated." Because (as noted in Variables from External Sources): "Dots and spaces in [external] variable names are converted to underscores."
External Variable Typecasting: Summary
A query string's values will always be strings, or arrays (of arrays) with strings as their final scalar values.
A query string's keys will always be strings, excepting whole numbers (unsigned positive: 3, signed negative: -3) that are cast as integers instead.
the query string itself is a string, but variables from it may be parsed as string or array:
url.com?var=123 => var is string
url.com?var[]=123&var[]=321 => var is an array
Yes it contains.
It can have any type you want, including array, integers, floats etc..
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})))
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';
I don't understand this array accessing syntax:
$target[$segs[count($segs)]]
Is it really possible to use variables as multidimensional array keys?
That might result in an error, if $segs is a numerical array with continuous indices only.
Meaning, it would fail for:
array("foo","bar");
but work for
array("foo", 2=>"bar");
Assuming now, that we deal with the first case, then this would work:
$target[$segs[count($segs) - 1]]
First, count($segs) - 1 will be evaluated and return a number. In this case the last index of $segs (provided it is a numerical array).
$segs[count($segs) - 1] will therefore return the last element in $segs. And whatever that value is, will be used as index for $target[...].
To sum up: It is nested array indexing and evaluated inside out.
See it in action.
Whether or not such a method is necessary depends on the problem you are trying to solve. If you don't know where you would use such nested, variable array indexing then you probably don't need it.
That syntax is fine, provided $segs is an array. It's worth noting, though, that if you're using a numerically indexed array for $segs, calling count($segs) is a non-existent key because indexing starts at zero.
I'm trying to create an associative array like this:
$key = '0'
$arr = array((string)$key=>$value);
Later, checking is_string(array_keys($arr)[0]) returns false.
The casting didn't help, using " instead of ' didn't help.
Am I doing something wrong, or is there another way around this, or is it impossible to have a numeric string array key?
In PHP, strings are converted to numbers when used as index, if they are purely numeric. When assigning it as an array key, it is converted to an integer, and same on access, you can use $arr['0'] to access the key 0.
PHP handles indexes of arrays in a bit more special way than just assigning to variables. Rules are clearly written in manual. Here is excerpt regarding your question.
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.
Quote from
http://php.net/manual/en/language.types.array.php
Set as Integer, but Accessible as String...
It appears that the keys will be assined the type of "integer" unless something about their value prevents the assignment. You are able to access them as strings, as I demonstrate with the gettype() line.
$array = array("0" => "Jonathan", "1" => "Sampson");
$keys = array_keys($array);
print gettype((string)$keys[0]); // string
when assigning values to a variable that could possibly be interpreted as multiple different types NEVER rely on them to actually be a specific type.