I am dealing with very strange issue of dealing with garbage in iterating through variable which has been cast to an array
$arr = (array)$var; // problem
$arr = array($var); // ok
The first method seems to work fine on values with integers, but not with strings. Is there any documented difference and does php have real casting ?
The problem is with lavarel 4, Database sources, function on line 704
If $var is a scalar, it's documented that both lines do the same:
For any of the types: integer, float, string, boolean and resource, converting a value to an array results in an array with a single element with index zero and the value of the scalar which was converted. In other words, (array)$scalarValue is exactly the same as array($scalarValue).
http://www.php.net/manual/en/language.types.array.php#language.types.array.casting
There are two ways to cast a variable in PHP as a specific type.
using the settype() function
using (int) (bool) (float) etc
More Info : http://www.electrictoolbox.com/type-casting-php/
Related
I came across (array) in WordPress in the following code but looked in the PHP manual search for (array) but could not find anything (https://www.php.net/manual-lookup.php?pattern=%28array%29&scope=quickref)
foreach ( (array) $cron as $timestamp => $hooks) {
foreach ( (array) $hooks as $hook => $args ) {
$key = md5(serialize($args['args']));
$new_cron[$timestamp][$hook][$key] = $args;
}
}
Could someone please explain what this (array) does?
This is called casting a variable (AKA casting or type-juggling). You are saying you want $cronhooks to be converted to and evaluated as an array. Look at this example:
$a = (int) 5.3;
print($a);
5
The (int) indicates that I want an integer from 5.3. so the PHP convert it.
It's casting the variable to an array. Perhaps $cronhooks was an object rather than an array, and could not be iterated as a key => value array.
Here's the manual page for Type Jugling in PHP
https://www.php.net/manual/en/language.types.type-juggling.php
Array members can be accessed using index or key as follow:
$cronhooks[0]; // the first member
$people['tom']; // the member with the key 'tom'
objects and classes have members which are accessed using the object operator:
$person->name; // name property of a person object
$person->save(); // might be a method to save the person back to the database
Interestingly wordpress has a built in internal function called _get_cron_array() which should return the cron jobs as an array.
Currently that source code is here:
https://github.com/WordPress/WordPress/blob/056b9c47a2114a23e9a892df2d5f79856dbe5a73/wp-includes/cron.php#L924-L945
But even in their own code they are casting it to array, which seems odd given the function professes to return an array in it's name!
That one casting example:
https://github.com/WordPress/WordPress/blob/056b9c47a2114a23e9a892df2d5f79856dbe5a73/wp-includes/cron.php#L95
Anyway this was fun to explore :D
This is infact known as type-juggling, or type-casting.
In some cases (such as int to float, int to string, string to an array, int to an array) the type will be converted (allowing a regular string or int to be looped though as in the example above).
However, some types cannot be effectively converted to another, such as an array to a string, int, or class object for some examples and PHP will issue a notice such as:
Notice: Array to string conversion in /path/file.php on line 10
and the array will be converted to a string with the contents "Array". However your PHP will not throw an error so the script will continue and not work as you probably expected.
This question already has an answer here:
How does the "Array dereferencing" work on a scalar value of type boolean/integer/float/string as of PHP version 7.2.0?
(1 answer)
Closed 5 years ago.
This is just a simple question out of curiosity. I spent the whole day debugging my PHP code, and found the problem was due to treating an integer as an array:
$x = $int[$index]; // this returns null, but no error at all
The integer was actually meant to be an array, but the function that was meant to pass the array messed up and passed the first value in the array instead. Is there any reason why an error isn't shown? Accessing an undefined index on an array creates an error, however trying to access a non-existent index on an integer doesn't?
I originally thought; it typecasts $int to a string because [] is another way of accessing string positions. Seems plausible that that wouldn't generate an error:
$string 'Hello';
echo $string[0]; // H
However, that's not the case:
$int = 1;
echo $int[0];
Outputs nothing and var_dump($int[0]) returns NULL.
Interestingly, the same behavior is exhibited for bool and float and the operation used is FETCH_DIM_R which is Fetch the value of the element at "index" in "array-value" to store it in "result".
From the manual Arrays:
Note: Array dereferencing a scalar value which is not a string silently yields NULL, i.e. without issuing an error message.
Similar to this phenomenon, where no error is generated. Bugs #68110 and #54556:
$array['a'] = null;
echo $array['a']['non-existent'];
Not surprising that assigning doesn't work:
$int = 1;
$int[0] = 2;
Warning: Cannot use a scalar value as an array
So PHP is actually attempting to access the int, bool, float as an array but not generating an error. This is from at least version 4.3.0 to 7.2.2.
Contrary to my original theory that you're invoking undefined behavior, this behavior actually is defined in the Array documentation.
Note:
Array dereferencing a scalar value which is not a string silently yields NULL, i.e. without issuing an error message.
In that case, it seems like there's no type juggling happening at all, so these references to documentation regarding conversion to array aren't useful in understanding this.
Explicit conversion to array is defined.
For any of the types integer, float, string, boolean and resource, converting a value to an array results in an array with a single element with index zero and the value of the scalar which was converted. In other words, (array)$scalarValue is exactly the same as array($scalarValue).
Automatic conversion to array is undefined according to the type juggling documenation.
Note:
The behaviour of an automatic conversion to array is currently undefined.
At first I thought this was what was happening in this case, but since salathe pointed out that this behavior is documented elsewhere, I'm not sure what "automatic conversion to array" is.
As to why this gives you a null value without throwing an error, warning, or notice, that's just how the PHP interpreter was implemented, and as far as why that is the case, it's not really answerable here. You'd have to ask the developers, and they might be able to tell you.
this is "type juggling", a "feature" of PHP.
you can read more in the official doc
EDIT
According to documentation, "The behaviour of an automatic conversion to array is currently undefined."
I run a quick test, just for curiosity:
<?php
$int = 1;
$index = 0;
$x = $int[$index];
echo gettype($int[$index]) . PHP_EOL;
var_dump($x);
and the output shows that gettype() returns NULL, so I guess that, in this case, is converted to NULL
I wanted to check for matching values in multiple arrays, so I made a multi-dimensional array by pushing them into $array and then wrote this line of code:
$result = call_user_func_array('array_intersect', $array);
I am getting the result I want, but I am always getting this notice on that particular line of code:
Notice: Array to string conversion
Wondering what's causing this. Hope someone can enlighten me.
Your arrays (the first-level items inside $array) themselves contain arrays. This is unsupported by array_intersect, because it treats the array items as strings for purposes of determining equality:
Note: Two elements are considered equal if and only if (string) $elem1 === (string) $elem2.
In words: when the string representation is the same.
I can't say definitely without knowing what exactly you are trying to do, but a possible solution is to use array_uintersect instead which will allow you to specify in code how to compare items without necessarily casting them to string.
$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.
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.