标题:php把字符串当作数组处理时的一段逻辑 出处:Felix021 时间:Mon, 18 Jan 2010 17:53:18 +0000 作者:felix021 地址:https://www.felix021.com/blog/read.php?1823 内容: 今天windy在群里提出一个问题: 为什么下面这段代码输出了why?$arr = 'windy'; if (isset($arr['why'])) { echo 'why'; } 因为已经有结果了,反推过去,很容易就会想到,php把字符串当作数组来用了。再通过echo $arr['why']; 验证一下,发现输出的是w, 也就是$arr{0}的值,可以大致得出一个结论:当把字符串当作数组使用的时候,会自动把索引转换成整形,然后再当作字符串的偏移量读取返回。 由于此结论仅为猜测,想进一步证实,但是对php代码不熟悉,翻了zend_hash.c等文件都没找到北,因此请教了雪候鸟大人,得知真正的处理代码位于 @ php-5.2.8/Zend/zend_execute.c +1026static void zend_fetch_dimension_address(temp_variable *result, zval **container_ptr, zval *dim, int dim_is_tmp_var, int type TSRMLS_DC) 这个函数的作用是:将container_ptr所指向的container这个容器中,索引为dim的值取出放在result所指定的内存中去。 具体实现的代码是1063 switch (Z_TYPE_P(container)) { 1064 zval **retval; .... 1099 case IS_STRING: { //如果这个容器是string 1100 zval tmp; 1101 1102 if (dim == NULL) { 1103 zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); 1104 } 1105 1106 if (Z_TYPE_P(dim) != IS_LONG) { //如果偏移量的类型不是LONG 1107 switch(Z_TYPE_P(dim)) { 1108 /* case IS_LONG: */ 1109 case IS_STRING: 1110 case IS_DOUBLE: 1111 case IS_NULL: 1112 case IS_BOOL: 1113 /* do nothing */ //允许STRING, DOUBLE, NULL, BOOL四种类型 1114 break; 1115 default: //其他类型都报错 1116 zend_error(E_WARNING, "Illegal offset type"); 1117 break; 1118 } 1119 1120 tmp = *dim; 1121 zval_copy_ctor(&tmp); 1122 convert_to_long(&tmp); 1123 dim = &tmp; //将原来的dim转换成LONG 1124 } 1125 switch (type) { 1126 case BP_VAR_R: 1127 case BP_VAR_IS: 1128 case BP_VAR_UNSET: 1129 /* do nothing... */ 1130 break; 1131 default: 1132 SEPARATE_ZVAL_IF_NOT_REF(container_ptr); 1133 break; 1134 } 1135 if (result) { //存放结果 1136 container = *container_ptr; 1137 result->str_offset.str = container; 1138 PZVAL_LOCK(container); 1139 result->str_offset.offset = Z_LVAL_P(dim); 1140 result->var.ptr_ptr = NULL; 1141 if (type == BP_VAR_R || type == BP_VAR_IS) { 1142 AI_USE_PTR(result->var); 1143 } 1144 } 1145 return; 1146 } 1147 break; 简单写了一点注释,只能大致看懂逻辑,其他边边角角的,暂时就没时间看了:'( Generated by Bo-blog 2.1.0