Jan
18
php把字符串当作数组处理时的一段逻辑
今天windy在群里提出一个问题: 为什么下面这段代码输出了why?
因为已经有结果了,反推过去,很容易就会想到,php把字符串当作数组来用了。再通过
由于此结论仅为猜测,想进一步证实,但是对php代码不熟悉,翻了zend_hash.c等文件都没找到北,因此请教了雪候鸟大人,得知真正的处理代码位于
@ php-5.2.8/Zend/zend_execute.c +1026
具体实现的代码是
简单写了一点注释,只能大致看懂逻辑,其他边边角角的,暂时就没时间看了:'(
转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php 。
$arr = 'windy';
if (isset($arr['why'])) {
echo 'why';
}
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 +1026
static 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;
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;
简单写了一点注释,只能大致看懂逻辑,其他边边角角的,暂时就没时间看了:'(
欢迎扫码关注:
转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php 。
sandy
2010-1-19 11:14
所以说任何框架都不可能达到完全的封装。。。要想成为高手还得去了解其内部的东西。。而这样又引入过多的相关性。。复杂性又随之而来。。咳咳
felix021 回复于 2010-1-19 11:19
是啊 引入更高的复杂性来解决现有复杂性带来的问题,往往会导致恶性循环。
分页: 1/1
1

