zoukankan      html  css  js  c++  java
  • PHP7.1与PHP5.6的版本中foreach以及string的差异

    刚用指针解答一到算法题,联想到一些问题,在此记录

    $arr = array( 1 => "start", 'wd' =>111, 3 => 333, "lz" => 4444, 55 =>"end" );
    
    // foreach循环在PHP5.6中是通过数组指针的移动实现的遍历,而在PHP7中有所改变
    foreach($arr as $key => $value){
        echo "<br />$key =>$value";
    }
    $k = key($arr);          // foreach结束后,指针的位置
    $v = current($arr);      // foreach结束后,指针的位置所指向的值
    $res = next($arr);       // foreach结束后,通过next()向下移动指针
    
    echo "<br />此时(遍历之后),“位置”为:"; var_dump($k);
    echo "<br />此时(遍历之后),对应“值”为:"; var_dump($v);
    echo "<br />此时(遍历之后),指针移向相下一个位置 :"; var_dump($res);
    exit;
    

    PHP5.6的输出如下:

    // $arr = array( 1 => "start", 'wd' =>111, 3 => 333, "lz" => 4444, 55 =>"end" );  // 参考原数组
    
    1 =>start        // 键值对    
    wd =>111            
    3 =>333
    lz =>4444
    55 =>end
    
    此时(遍历之后),“位置”为:NULL
    此时(遍历之后),对应“值”为:bool(false)
    此时(遍历之后),指针移向相下一个位置 :bool(false)
    

    PHP7.1的输出如下:

    1 =>start
    wd =>111
    3 =>333
    lz =>4444
    55 =>end
    此时(遍历之后),“位置”为:int 1
    
    此时(遍历之后),对应“值”为:string 'start' 
    
    此时(遍历之后),指针移向相下一个位置 :int 111
    

    区别

    • PHP5.6中数组遍历后,是移动的指针,移呀移呀,就不在数组的有效范围内了。故此,执行各种操作都是NULL或false
    • PHP7.1中,遍历后指针仍在数组的头部,因为按照值进行循环的时候, foreach是对该数组的副本操作,原数组指针并未移动,故此可以继续执行指针操作。

    $arr = array( 1 => "start", 'wd' =>111, 3 => 333, "lz" => 4444, 55 =>"end" );
    foreach($arr as $key => $value){
        echo current($arr);            // 全部输出 start, 说明$arr的指针并未移动
        // echo "<br />$key =>$value";
    }
    $k = key($arr);
    $v = current($arr);
    $res = next($arr);
    echo "<br />此时(遍历之后),“位置”为:"; var_dump($k);
    echo "<br />此时(遍历之后),对应“值”为:"; var_dump($v);
    echo "<br />此时(遍历之后),移向相下一个位置是否成功:"; var_dump($res);
    $res = next($arr);  // 仅加入几行next()和一行输出,其他代码一样
    $res = next($arr);
    $res = next($arr);
    $res = next($arr);
    echo "<br />此时(next移动到数组尾端后),移向相下一个位置是否成功:"; var_dump($res);
    exit;
    

    PHP7.1输出如下

    startstartstartstartstart
    
    此时(遍历之后),“位置”为:
    D:workspacegitlabwater.service.klagri.com.cndevindex.php:10:int 1
    
    此时(遍历之后),对应“值”为:
    D:workspacegitlabwater.service.klagri.com.cndevindex.php:11:string 'start' (length=5)
    
    此时(遍历之后),移向相下一个位置是否成功:
    D:workspacegitlabwater.service.klagri.com.cndevindex.php:12:int 111
    
    此时(next移动到数组尾端后),移向相下一个位置是否成功:
    D:workspacegitlabwater.service.klagri.com.cndevindex.php:17:boolean false
    
    • 由结果可以看出来,next()到数组最后一个位置后,再进行next()返回false,跟5.6的foreach一样。

    ----------------------------------------------------------------------分割线----------------------------------------------------------------------------------------

    下面再来说说string的一切区别

    • 请看下面这段代码,将罗马数字转为整数
        $s = "LVIII";   // 罗马数字58
        $rome = ["I"=>1, 'V'=>5, 'X'=>10, 'L'=>50, 'C'=>100, 'D'=>500, 'M'=>1000];
        $len = strlen($s);
        $sum = 0;
        for($i=0; $i<$len; $i++){
            $sum += $rome[$s[$i]];
            if(isset($s[$i-1]) && ($rome[$s[$i-1]] < $rome[$s[$i]])){
                $sum -= $rome[$s[$i-1]]*2;
                if(isset($s[$i-2]) && ($rome[$s[$i-2]] < $rome[$s[$i-1]])){
                    $sum -= $rome[$s[$i-2]]*2;
                }
            }
        }
        var_dump($sum);exit;
    
    • 用PHP5.6运行,结果是58
    • 用PHP7.1运行,结果是56

    原因分析

     $s = "LVIII";
     echo $s[-1];exit;
    
    • 这两行代码,
      • 用PHP5.6执行,Notice: Uninitialized string offset: -1
      • 用PHP7.1执行,结果为I
    • PHP7支持了反向索引,查看了下源码,无论输入正负索引,最终都会转为正序索引。
         if (UNEXPECTED(Z_STRLEN_P(container) < (size_t)((offset < 0) ? -offset : (offset + 1)))) {
    (gdb) s
        1861 ? (zend_long)Z_STRLEN_P(container) + offset : offset;
        我认为这两行最主要,与索引位置查找相关。下面个zend_string_init 是一个赋值操作
    
        zend_string_init (persistent=0, len=1, str=0x7ffff145563c "I") //str为73 I的ASCII码
        memcpy(ZSTR_VAL(ret), str, len);
    
    看的不是太懂,第一次看源码也有点晕,找到这个之后,一下退出断点了,就没二次查找
    
    总之,不论正负索引,在最后都会转化为正确的正序索引。
    

    总结

    使用foreach时,要注意PHP版本,同时要知道产生差异的原因: 一个是移动原数组指针,一个是移动副本的指针。了解原理才能更好的使用。
    使用string 进行索引是否存在的判断是,要注意PHP版本,$str[-1]在PHP5.6中代表字符串之前的地址,显然是不存在的,在PHP7中代表从后往前数第一个字符。
    建议工作中使用多个PHP版本的猿们做好兼容处理,避免产生问题。

  • 相关阅读:
    mysql dbrd脑裂问题
    iOS 跳转至AppStore评分页面
    UIButton的titleLabe setAttributeSting 首次不起作用
    IOS ScrollView放大缩小点击位置并居中
    UIScrollView 性能优化
    iOS UIButton单双击处理响应不同的方法
    正则表达式过滤手机号
    iOS8通讯录之联系人增删查,多号码增删操作
    CoreData 添加新字段
    一张图教你搞定Mac App Store 应用安装包存储路径
  • 原文地址:https://www.cnblogs.com/lz0925/p/12171331.html
Copyright © 2011-2022 走看看