V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gdtv
V2EX  ›  PHP

php foreach 是传值还是传引用?

  •  
  •   gdtv · 2016-07-10 17:55:12 +08:00 · 2919 次点击
    这是一个创建于 3062 天前的主题,其中的信息可能已经有所发展或是发生改变。

    先感谢此网页给我的指导 http://www.netingcn.com/php-foreach-pass-value-reference.html 现在我得知: 如果数组里面存放的是普通类型的元素就是采用传值的方式,存放对象类型元素采用的方式为传地址。

    代码:

    $raw_arr = array(
        (object)(array('id' => 1, 'name' => 'name1')),
        (object)(array('id' => 2, 'name' => 'name2')),
    );
    foreach ($raw_arr as $value) {
        $new_value = $value; //这里也是引用???
        $new_value->name = $new_value->name  . '-modify';
    }
    print_r($raw_arr);
    

    输出:

    Array
    (
        [0] => stdClass Object
            (
                [id] => 1
                [name] => name1-modify
            )
    
        [1] => stdClass Object
            (
                [id] => 2
                [name] => name2-modify
            )
    
    )
    

    我的问题: 我想在 foreach 循环内将$value 传值给一个新变量$new_value ,我希望对$new_value 的任何操作都不会影响原始数组$raw_arr, 请问该怎么做呢?

    第 1 条附言  ·  2016-07-24 10:40:39 +08:00
    感谢大家回复,最后的采用的方法是:$object = unserialize(serialize($object))
    11 条回复    2016-07-12 08:54:48 +08:00
    shyling
        1
    shyling  
       2016-07-10 19:07:52 +08:00
    复制引用的形式。。
    falcon05
        2
    falcon05  
       2016-07-10 19:11:13 +08:00 via iPhone   ❤️ 1
    clone
    shiny
        3
    shiny  
       2016-07-10 19:20:04 +08:00
    因为这个是 Object ,其他类型不受影响
    moult
        4
    moult  
       2016-07-10 21:12:05 +08:00
    一般情况下,对象传引用,基本数据类型传值。
    如果变量前面有取地址符&的话,那么基本数据类型也是传引用。
    ```
    <?php
    $list = array(1,2,3);
    foreach($list as &$value){
    $value = $value*2;
    }
    unset($value);
    var_dump($list);
    ```

    另外,友情提醒,变量记得 unset 掉,不然会有大彩蛋的。
    moult
        5
    moult  
       2016-07-10 21:16:39 +08:00   ❤️ 2
    抱歉,回复的时候没有看仔细。
    $new_value = clone $value;
    但要任何操作都不会影响,还是得看这个 Object 实现了,__clone()魔法函数可以控制拷贝深度!
    dawniii
        6
    dawniii  
       2016-07-11 06:55:37 +08:00
    @moult 话说大彩蛋是什么呢?
    moult
        7
    moult  
       2016-07-11 13:09:43 +08:00
    @dawniii
    在执行 foreach($array as &$item) 之后,如果$item 没有 unset 的话,那么$item 这个变量始终指向$array 的最后一个元素。
    也就是如果下面编码的时候没注意,来了个$item='foo_bar'的话,那么 end($array)==='foo_bar',导致$array 内容离奇得不对!尤其是第一年工作的时候,遇到过好几次。。
    所以 foreach 的时候,如果要修改源数组内容,尽量少用&,最好 foreach($array as $key=>$item)!
    当然,如果 foreach 里面没有 break 场景的话,用 array_walk 更好。
    gdtv
        8
    gdtv  
    OP
       2016-07-11 13:23:22 +08:00
    @moult 就算不用&,如果$array 的元素的类型是 object ,还是引用
    szopen
        9
    szopen  
       2016-07-11 15:10:21 +08:00
    在 PHP 7 foreach 默认是复制,详细变更见: https://wiki.php.net/rfc/php7_foreach
    Balthild
        10
    Balthild  
       2016-07-11 15:44:28 +08:00
    这么说的话,假如$var1 是 Object ,那$var2 = $var1;实际上是把这个对象的地址给了 $var2 ,而不是复制了一个对象实例?
    nec
        11
    nec  
       2016-07-12 08:54:48 +08:00
    如果要改变原数组的值,并且原数组不为对象数组(即为基本数据类型数组),那么就传引用

    上代码:

    $bk_cart_arr = ['1:1','2:1','3:2'];
    $product_id = 1;
    $count = 1;
    foreach ($bk_cart_arr as &$value) { //传引用
    //拿到数组中的每个字符串,并且使用 strpos ()来获取:的位置)
    $index = strpos($value, ":");
    if (substr($value, 0, $index) == $product_id) {
    $count = ((int)substr($value, ($index + 1))) + 1;
    $value = $product_id . ':' . $count;
    break;
    }
    }
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1234 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 18:05 · PVG 02:05 · LAX 10:05 · JFK 13:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.