(bool)true var在数组赋值时没有转换为数组,但是(bool)false。为什么?

时间:2010-07-12 20:34:32

标签: php arrays

使用PHP ......一个例子。这会产生警告 - 如预期的那样 - 并且$myVar保持为bool(true)。

$myVar = true;
$myVar[] = 'Hello';  // Warning: Cannot use a scalar value as an array

但是下一个例子'工作',$myVar被转换为一个单元素'Hello'的数组。

$myVar = false;
$myVar[] = 'Hello';  // Converted into an array

结果:

array(1) {
  [0]=>
  string(5) "Hello"
}

然而bool(true)和bool(false)都是标量。为什么差异呢? PHP中的什么规则控制着这种行为?或者它是'它的方式'?!

我最初认为它可能与类型转换规则有关,但bool(true)和bool(false)在这方面表现相同。

感谢。

4 个答案:

答案 0 :(得分:7)

所以,即使我不知道为什么 PHP这样做,我看了一些Zend代码,至少可以告诉你在哪里可以找到PHP的确切方式。

因此,重要的代码在zend_fetch_dimension_address

所以,让我们来讨论上述情况:

如果IS_ARRAY - 一切都很明显。

如果它IS_OBJECT抛出错误,除非它有ArrayAccess

如果IS_STRING抛出错误,除非字符串长度为零

如果IS_NULL创建新阵列

如果IS_BOOL抛出错误,除非错误

否则,抛出错误。

所以,这证实了你和我的测试:

如果是对象,非空字符串,true和其他标量,即long和double,则会出错。 数组,空字符串nullfalse没有错误。所以基本上它会对大多数(但不是全部)“虚假”值进行自动投射。

答案 1 :(得分:1)

PHP不是强类型语言。您将数组分配给包含false值的变量,而不是布尔 false值。

在PHP封面下,它必须将$myVar视为具有值为空的值,因此允许数组赋值。

同样,如果你将PHP看作一种动态脚本语言,那就不是那么出乎意料了。

答案 2 :(得分:1)

如果您想知道为什么会这样,那么请检查php from here I think,编译它并使用gdb进行一些逐步调试...除非有人足够好找到这段代码对此负责。 然后查看负责此操作的代码周围的注释(如果有的话)。 正如下面的评论中所提到的,找到的另一种方法是搜索代码以查找错误消息。我们这样做!

    [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

看起来像是在zend_execute.c中,这是我发现的:

 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; 

我认为ZLVAL_P(container)==0条件是造成这种差异的原因... lval表示左值,正在分配的值...我认为它的计算结果为0.

答案 3 :(得分:0)

虽然PHP是松散类型的,但类型仍然具有一定的重要性,因此===或!==例如。

如果Nikic重置为零,它会出现错误的原因是它实际上现在是一个整数,而不是一个布尔值。

为了演示,您可以执行以下操作并通过强制转换获得相同的错误。

$a = (int) false;
$a[] = 'goat'; #throws warning, thinks it's a 0

$a = (bool) 0;
$a[] = 'goat'; #works, thinks it's a false

我知道这只是一个迂腐的例子! (bool)true仍然评估为1。