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.
Related
While doing some code refactoring I momentarily ended up in a situation where I was basically doing the (somewhat abstracted-out) equivalent of
$data = (object)json_decode('"test"');
Of course I understand json_decode() generates objects on its own unless assoc is false. (Incidentally I got into this situation because I was in the middle of moving some format processing code around, and I hadn't yet realized one of my (object) casts was now redundant.)
But... when this happened, PHP decided that $data contained:
stdClass Object
(
[scalar] => test
)
Wat.
scalar?!
Last I learned, "test" is a string, so it seems more than one pile of things has fallen over internally here. Or is this unintuitive yet intended design?!
I have of course removed the (object) and things work exactly how I intended now. So there's no bug here per se. I just wanted to understand what just happened.
Here you go, in case you want to join in the headscratching:
php -r 'print_r((object)json_decode("\"test\""));'
I'm using 7.0.25.
This is exactly what the manual specifies will happen when casting a scalar type (i.e. int, string, float, boolean) to an object.
If an object is converted to an object, it is not modified. If a value of any other type is converted to an object, a new instance of the stdClass built-in class is created. If the value was NULL, the new instance will be empty. An array converts to an object with properties named by keys and corresponding values. Note that in this case before PHP 7.2.0 numeric keys have been inaccessible unless iterated.
For any other value, a member variable named scalar will contain the value.
$obj = (object) 'ciao';
echo $obj->scalar; // outputs 'ciao'
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've noticed something quite strange with PHP Objects and can't find a documented cause of it.
The following code demonstrates the behaviour
<?php
$a = (object) array( 0 => 1 );
foreach($a as $b => $c) {
$a->$b = ++$c; //I'm expecting the key to be overwritten here
}
var_dump($a);
$var = 0;
var_dump($a->$var);
$var = "0";
var_dump($a->$var);
and the output
object(stdClass)#1 (2) {
[0]=>
int(1)
["0"]=>
int(2)
}
int(2)
int(2)
Is the numeric part of the class inaccessible using -> syntax?
When you perform an (object) cast on an array you promote that array as the internal property list of an anonymous object (i.e. stdClass).
The way properties are indexed in an object is slightly different than that of an array; specifically, object property names are always treated as strings whereas array indices are looked up based on the intended type (e.g. numeric strings are seen as integers).
The above behaviour doesn't affect foreach loops because there's no hashing involved there; as far as PHP is concerned, a regular array is being iterated.
To answer your question, yes, the numeric keys from your original array can't be accessed using the -> operator. To avoid this you should remove the numeric indices from your array before the cast is performed.
It's hard to find this behaviour in the documentation, but a hint of it can be found here:
If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible ...
FYI
In this particular case you can circumvent the issue by using references; this is not recommended, please follow the earlier advise of not using numeric property names:
foreach ($a as &$c) {
++$c;
}
unset($c);
Update
2014-11-26: I've updated the documentation; the live pages will be updated this Friday - commit.
stdClass handles data terribly loosely, since it's an object representation of an internal array (thus the ability of of casting without problems).
$stdClassObject->property = "value";
The property is handled as a string, but upon casting, the property type doesn't change (which is somehow understandable, as if you cast to an object and then to an array again, you'd have lost all the integer indexes).
I don't think they could do better than that, but you can create your own alternative to stdClass :-)
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/
EDITED:
I am generating a 2D array and storing it in db as json string. When I need to modify anything in the array, I then fetch the json string and decode it like
$myarray = (array)json_decode($jsonString);
The dump of array is as
$index = 2;
When I wan to access object at index '2' like $myarray[$index] I get null. Please guide what I am doing wrong?
In your comment you said this "array" was decoded from JSON. When you use json_decode, send true as the 2nd parameter. That tells it to make arrays instead of objects when decoding.
You're having trouble because the array is being decoded as an object, which you access using -> instead of [].
$newArray = json_decode($jsonString, true);
UPDATE: You were trying to do (array)json_decode($jsonString) and that wasn't working. That's because PHP is silly when it comes to type-casting.
Here's a quote from the PHP docs:
If an object is converted to an array, the result is an array whose
elements are the object's properties. The keys are the member variable
names, with a few notable exceptions: integer properties are
unaccessible; private variables have the class name prepended to the
variable name; protected variables have a '*' prepended to the
variable name. These prepended values have null bytes on either side.
This can result in some unexpected behaviour.
Source: http://php.net/manual/en/language.types.array.php#language.types.array.casting
So, it wasn't working because PHP said so.
try with
$index = '2';
I think you defined the array as associative.