(bool)true var does not get converted to array on array assignment, but (bool)false does. Why?
Using PHP... an example. This produces a warning - as expected - and $myVar
stays as bool(true).
$myVar = true;
$myVar[] = 'Hello'; // Warning: Cannot use a scalar value as an array
But this开发者_运维技巧 next example 'works', $myVar
is converted into an array with a single element 'Hello'.
$myVar = false;
$myVar[] = 'Hello'; // Converted into an array
Results in:
array(1) {
[0]=>
string(5) "Hello"
}
Yet both bool(true) and bool(false) are both scalar. So why the difference? What rule in PHP governs this behaviour? Or is it 'just the way it is'?!
I initially thought it might be to do with type casting rules, but both bool(true) and bool(false) behave the same in this respect.
Thanks.
So, even though I don't know why PHP does that, I looked at some Zend code and can at least tell you where you can find out how exactly PHP does it.
So, the important code is in zend_fetch_dimension_address
.
So, let's cover the above cases:
If it IS_ARRAY
- everything obvious.
If it IS_OBJECT
throw error unless it has ArrayAccess
.
If it IS_STRING
throw an error, unless the strings length is zero.
If it IS_NULL
create a new array.
If it IS_BOOL
throw an error, unless it is false.
Otherwise, throw an error.
So, this confirms your and my tests:
Error if object, non-empty string, true
and other scalars, i.e. long and double.
No error if array, empty string, null
and false
. So basically it does an automatic cast on most (but not all) "falsy" values.
PHP is not a strongly typed language. You are assigning an array to a variable that contains a false
value, not necessary a boolean false
value.
Under the PHP covers, it must see $myVar
as having an value that evaluates as empty and therefore allows the array assignment.
Again, if you look at PHP as a dynamic scripting language, this is not all that unexpected.
If you want to know why it is like this, then checkout php from here I think, compile it and do some step-by-step debugging with gdb... unless someone is good enough to find the piece of code responsible for this. Then look at the comments (if there are some) around the code responsible for this. As mentioned in the comments below, another way to find out would be to search the code for the error message. Let's do this!
[greg@liche php-src-5.3]$ grep -rn --exclude-dir=".svn" "Cannot use a scalar value as an array" .
./tests/lang/bug29893.phpt:10:Warning: Cannot use a scalar value as an array in %sbug29893.php on line %d
./tests/lang/engine_assignExecutionOrder_002.phpt:12:// Warning: Cannot use a scalar value as an array in %s on line %d
./tests/lang/engine_assignExecutionOrder_002.phpt:94:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/zend_execute.c:1015: zend_error(E_WARNING, "Cannot use a scalar value as an array");
./Zend/tests/indexing_001.phpt:51:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:54:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:57:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:77:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:96:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:99:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:102:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:119:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:137:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:140:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:143:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:160:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:179:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:182:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:185:Warning: Cannot use a scalar value as an array in %s on line %d
./Zend/tests/indexing_001.phpt:202:Warning: Cannot use a scalar value as an array in %s on line %d
looks like it is in zend_execute.c, here is what I found :
case IS_BOOL:
1223 if (type != BP_VAR_UNSET && Z_LVAL_P(container)==0) {
1224 goto convert_to_array;
1225 }
1226 /* break missing intentionally */
1227
1228 default:
1229 if (type == BP_VAR_UNSET) {
1230 zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
1231 AI_SET_PTR(result, &EG(uninitialized_zval));
1232 PZVAL_LOCK(&EG(uninitialized_zval));
1233 } else {
1234 zend_error(E_WARNING, "Cannot use a scalar value as an array");
1235 result->var.ptr_ptr = &EG(error_zval_ptr);
1236 PZVAL_LOCK(EG(error_zval_ptr));
1237 }
1238 break;
I think the ZLVAL_P(container)==0
condition is responsible for this difference... lval means left value, the value that is being assigned... and I think it evaluates to 0.
Whilst PHP is loosely typed, types do still have some importance, hence === or !== for example.
The reason Nikic gets an error if it is reset to zero is it is actually now an integer, rather than a boolean.
To demonstrate, you could do the following and get the same error by casting.
$a = (int) false;
$a[] = 'goat'; #throws warning, thinks it's a 0
$a = (bool) 0;
$a[] = 'goat'; #works, thinks it's a false
I know thats just a pedantic example, however! (bool) true still evaluates to a 1.
精彩评论