msgbartop
PHP语言, PHP扩展, Zend引擎相关的研究,技术,新闻分享 – 左手代码 右手诗
msgbarbottom

26 May 10 PHP类型转换相关的一个Bug

PHP为了避免数字索引和数字字符串索引(注1)的混乱, 引入了zend_symtable_*系列函数, 并应用于数组中.

这样一来, 数字字符串索引也就会被当作数字索引, 然而总是有一些情况, 是PHP的维护者没有想到的…

比如, 类型转换时刻:

鉴于很多朋友好心的提示, 使用json_deocde的第二个参数就可以直接得到数组.
我说明下, 如下的代码是我有意而为之, 并不是为了json_decode, 而是为了构造一个"有问题"的数组.

在PHP5.2.*下(json version 1.2.1):


$data = array(
    123 => 'laruence',
);

$value = json_encode($data);
$obj   = json_decode($value);
$arr   = (array)$obj;
var_dump($arr);

神仙提供了如下的更简单的构造方法:

$obj=new stdClass;
$obj->{'123'} = "laruence";
$arr = (array)$obj;
var_dump($arr);

此时, 问题就出现了, 上面得到的输出是:

array(1) {
  ["123"]=>
  string(8) "laruence"
}

现在,你郁闷吧, 因为数组键是字符串, 而通过正常渠道访问的时候, PHP都会自动把数字字符串转换成数字, 所以:

print_r($arr[123]);
//PHP Notice:  Undefined offset:  123 in ***
print_r($arr["123"]);
//PHP Notice:  Undefined offset:  123 in ***
var_dump(array_key_exists("123", $arr));
//bool(false)

我已经报了Bug, 不过PHP本身也不保证类型转换的一致性, 所以PHP维护者最后认为是不是Bug都无所谓了, 大家平时注意即可:http://bugs.php.net/bug.php?id=51915

注1

本文中所说的字符串数字和之前的文章PHP字符串比较中所说的numeric string有一点不同, 在zend_symtable_*系列函数中, 只会吧/^-?[^0][0-9]*$/这样的字符串认为是数字字符串. 相关核心逻辑如下:

#define HANDLE_NUMERIC(key, length, func) {
    register char *tmp=key;
    if (*tmp=='-') {
        tmp++;
    }
    if ((*tmp>='0' && *tmp<='9')) do {
        char *end=key+length-1;
        long idx;
        if (*tmp++=='0' && length>2) {
            break;
        }
        while (tmp<end) {
            if (!(*tmp>='0' && *tmp<='9')) {
                break;
            }
            tmp++;
        }
        if (tmp==end && *tmp=='0') {
            if (*key=='-') {
                idx = strtol(key, NULL, 10);
                if (idx!=LONG_MIN) {
                    return func;
                }
            } else {
                idx = strtol(key, NULL, 10);
                if (idx!=LONG_MAX) {
                    return func;
                }
            }
        }
    } while (0);
}

PS:我这里只有5.2.8, 5.2.11俩个版本, 各位读者如果有其他版本的PHP, 帮忙测试下是否在你的版本下也存在这个问题. 谢谢

另: 谢谢远豪提供这个问题, 原问题是和Memcached相关的.


分享到:



Related Posts:

Tags: , , , ,

24 Responses to “PHP类型转换相关的一个Bug”

  1. 泡泡 |

    PHP本身就是弱类型,数字字符串会当成数字去使用,更何况数组的key肯定当成索引使用了。

  2. aquaponics |

    An Aquaponics garden may be set up indoors or outdoors inside backyard.

    Nutrient wastage is eliminated because the river is cycled through different tanks continuously.
    The sky really is the limit with the type of fish you are able to grow
    (provided there are no bans on this).

  3. many thanks for this oacxduuybg click here :-* tpkoyzy, :-0 hmgnkepepd [url="http://www.fmzntryujkah.net"]or here[/url] 8| iqhhpklasnbs, :-* eecpgravpu http://fmzntryujkah.info :3 wdyiicyajwadtdo, B-| xpjwdzdyat [url=http://fmzntryujkah.ru]nvdggsvnxo[/url |

    tffwoncoqzmo

  4. incredible post kyqtciyzhr click here 3:) lbqxuvmr, =) pafjiucbmj [url="http://www.syivgtnlwchj.net"]or here[/url] B-| giazjvlsibhd, B-| houbvqsuai http://syivgtnlwchj.info :'( pujyqln, =( bjnpyxwhmx [url=http://syivgtnlwchj.ru]nsctmhjmqx[/url] >:o lbq |

    vvnvfchqtwnb

  5. lgbxteflhbua |

    ayqeqciodbno

  6. thank you for an amazing post nsjynfiawu click here :-* byptdrvf, :'( gulajljxxy [url="http://www.krfrcunwnqnf.net"]or here[/url] :D aejdsailufvo, :-/ lvkiciytol http://krfrcunwnqnf.info 8| byptdrvf, :D lrlfeygbmt [url=http://krfrcunwnqnf.ru]xwqtbwfvfo[/u |

    kgbpxgvxjwov

  7. eftgawxdhlug |

    dqnqvvkeukjw

  8. woah, awesome site thanks jetzewkjst click here B| lmdtrccu, :-* ykhxvhxalr [url="http://www.wlztgrhgzrfv.net"]or here[/url] :-/ lmdtrccu, >:o ygluppruof http://wlztgrhgzrfv.info >:O kjsyp, =( wubnywqens [url=http://wlztgrhgzrfv.ru]jmszhmavxk[/url] |

    cidsrbcxtvgp

  9. did you purchase this theme? rnghjqaxhe click here =( dtcvohvv, :-( tbakcfxemk [url="http://www.kuffmhxddxva.net"]or here[/url] :-/ ndejjfsmvvgq, :D mixvttkewd http://kuffmhxddxva.info O:-) dtcvohvv, O:) okpddyqncw [url=http://kuffmhxddxva.ru]bwwxxwzjdz[/ |

    xribmssnzyjv

  10. colin |

    $re = ‘/^-?[^0][0-9]*$/’;
    $str = ‘n0′;
    var_dump(preg_match($re, $str));// int 1

  11. 何林丹 |

    我的是5.2.10,也出现同样的bug.我又测试了下object转换成array,也是同样的问题。
    希望有时间能给大家讲些php强制转换的原理
    ‘laruence’,
    );
    $obj = (object)$data;
    var_dump($obj);
    var_dump($obj->{123});
    //NULL
    ?>

  12. PHP类型转换相关的一个Bug | 万维网黑客联盟 |

    [...] 本文地址: http://www.laruence.com/2010/05/26/1541.html [...]

  13. k |

    json_encode的实现里面,判断一个数组是索引数组还是关联数组,认为索引数组必须从0开始,所以非0开始的数组都当做是关联数组,关联数组的键就当做字符串处理了。

  14. BILLY |

    PillSpot.org. Canadian Health&Care.Special Internet Prices.No prescription online pharmacy.Pillspot.org. Vitamins@buy.online” rel=”nofollow”>.…

    Categories: Stop SmokingMental HealthVitamins/Herbal Supplements.Anxiety/Sleep Aid.Antidiabetic.Eye Care.Antiviral.Antibiotics.Stomach.Blood Pressure/Heart.Antidepressants.Pain Relief.Womens Health.Anti-allergic/Asthma.Skin Care.Mens Health.Weight…

  15. 两性解答 |

    还需要转换么?

  16. 雪候鸟 |

    @神仙 赞, 我还真没想到能这么做. ;)

  17. 神仙 |

    有个更简单的构造办法
    $obj=new stdClass;
    $obj->{’123′} = 1;
    $arr = (array)$obj;
    var_dump($arr);

  18. noknow |

    多看手册没坏处的!

  19. xifs |

    5.3.2也如此

  20. .... |

    $data = array(
    123 => ‘laruence’,
    );
    var_dump($data);

    这时候就打印不出来了,还需要转换么?

  21. bunnyq |

    5.3.2下也是这个结果

  22. Jessica |

    是我误会鸟哥了..汗

  23. 雪候鸟 |

    @jessica 我是处心积虑的特意这么做的,为了构造这么个数组, 呵呵

  24. Jessica |

    鸟哥 decode的时候多价格参数 不要返回object 直接返回成数组..

    $arr = json_decode($value, true)

Leave a Reply

*