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

[吐槽] PHP :哪天没有写 bug,算我输。数组哪里都是值拷贝;引用:蛋疼。明明是语言问题,硬说是我太菜

  •  
  •   xiangyuecn · 2021-12-18 05:43:18 +08:00 · 3409 次点击
    这是一个创建于 1062 天前的主题,其中的信息可能已经有所发展或是发生改变。

    每隔几年都要来学一遍,每次都是入门到放弃。直接上代码,懒得解释。

    //常规脑回路,写的代码,抱歉了,bug 成堆
    
    $list=array();
    for($i=0;$i<10;$i++){
        $obj=array();
        $list[]=$obj; //后面会有 break 、return 等复杂逻辑,因此此处进行赋值代码量最少
        
        $obj["val"]=$i;
        //...一大堆复杂逻辑
    }
    
    //list= [{},{},{},......,{}]
    

    数组对象这么重要的东西,默认进行赋值操作竟然是值拷贝。每赋值一次,就整个数组复制一遍。不能说这种方式不妥吧,就是感觉不那么好,说不上来的那种不好!

    数组对象赋值采用引用的方式赋值,场景绝对比值拷贝多的多。需要做为全新的一个数组对象来对待的场景,完全可以显式的进行新数组的创建操作。直接就省去了很多麻烦。( PHP 也是老人家了,发了这么多版,随便出个 Array2 搞点完全不同的特性来糊弄我一下也行啊)

    //修改代码,显式的进行引用。依旧是常规脑回路,写的代码,抱歉了,bug 还是成堆
    
    $list=array();
    for($i=0;$i<10;$i++){
        $obj=array();
        $list[]=&$obj; //后面会有 break 、return 等复杂逻辑,因此此处进行赋值代码量最少
        
        $obj["val"]=$i;
        //...一大堆复杂逻辑
    }
    
    //list= [{val:9},{val:9},......,{val:9}]
    

    然后就有了,看似很屌,其实并没有多大卵用的:引用。有意思的是,它是按名字来引用,这个很关键,也很鸡肋。(在函数参数里面似乎有点儿卵用,就算没有引用传递这种东西,引用参数完全可以用别的带有引用性质的东西来代替)

    //好了,这回正常了。不过,我的脑回路已经不正常了,劝退中
    
    $list=array();
    for($i=0;$i<10;$i++){
        unset($obj); //强加的负担,迟早要翻车,漏了就反复调试来定位吧,一次写出的代码能用就怪了
                //这种形式的引用方式,不要也罢:赋值一次,所有变量乱窜
        $obj=array(); //如果你不是值拷贝,用得着引用?
        
        $list[]=&$obj; //后面会有 break 、return 等复杂逻辑,因此此处进行赋值代码量最少
        
        $obj["val"]=$i;
        //...一大堆复杂逻辑
    }
    
    //list= [{val:0},{val:1},......,{val:9}]
    

    php 代码:满屏的毫无意义的 $,满屏的毫无意义的两个字宽度的 -> ,代码看起来很肥 很保暖。

    狗屁不是。可以:解决掉有问题的人,就没有问题了。

    28 条回复    2022-09-09 14:39:59 +08:00
    t6attack
        1
    t6attack  
       2021-12-18 06:20:00 +08:00   ❤️ 2
    每门语言的特性不一样,好好的 php 非得按 java 的思路写。
    值传递很好,只有数组这一种数据结构很好。千万别按楼主的思路改。也不需要什么 Array2 。
    php 没有在不同版本瞎改,向前兼容做的很好,为 php 开发组点个赞。
    zjsxwc
        2
    zjsxwc  
       2021-12-18 07:28:24 +08:00 via Android
    PHP 的 for 中使用引用一直是潜在 bug 的源头。
    vanton
        3
    vanton  
       2021-12-18 08:46:07 +08:00
    为啥要在 for 里面引用?
    你这思路有点奇怪。
    每种语言有存在的意义 ,有自己的风格,硬要都按照 java 的思路去写不是找麻烦么。
    zjsxwc
        4
    zjsxwc  
       2021-12-18 09:01:37 +08:00
    其实楼主用面向对象的方式写就没有问题了:
    https://gist.github.com/zjsxwc/25e7388b777ba56b614fe7f3e9d2b126
    xiangyuecn
        5
    xiangyuecn  
    OP
       2021-12-18 09:46:08 +08:00
    @zjsxwc #2 #4 不是 for 的问题,是 Array 的问题。自己定义的对象,默认赋值就是引用,不存在隐式的复制,自然就不需要自己显式的引用赋值。Array 这个玩意败笔就在默认赋值一下就拷贝一遍,这就注定了逃不过用到&,最终结果就是不常用的引用功能,&要被滥用。

    所以我提出一个 Array2 ,理想状态下,默认赋值就是引用,我如果要复制,完全可以自己调用一个函数复制出一个新数组。对于解析器底层实现一个这玩意,我猜测应该也不复杂,比如给 Array 加一个标记,遇到这种特殊的 Array 类型的对象,解析器发现有标记,就跳过复制阶段,直接引用这个,就和对象一样对待应该就 OK 了。
    xiangyuecn
        6
    xiangyuecn  
    OP
       2021-12-18 09:51:47 +08:00
    @t6attack #1 @vanton #4 针对类似这种说法,所以我结尾直接提前写上了解决办法。

    很多相同逻辑,不管什么语言实现,写出的结构都会差不多,不会偏的离谱,我接触的比 php 更丑的还有 python 、vb ,不过他们没有这种不可思议的问题。

    “为啥要在 for 里面引用?”,这种问题也会成为问题,程序员忍不住的话要把菜刀放桌上了😂 逻辑实现除了 if for 还有什么是重要的?
    xiangyuecn
        7
    xiangyuecn  
    OP
       2021-12-18 09:55:17 +08:00
    @vanton #3 上面标错楼层了
    msg7086
        8
    msg7086  
       2021-12-18 12:45:38 +08:00 via Android
    第二段起手 数组对象 是什么勾八玩意儿?

    数组特么的就不是对象。张口闭口整篇文章就在谈一个不存在的东西我也是服了。

    数组就是数组。对象才是对象。搞不清楚数组是什么东西可以学,不知道数组和对象是什么关系可以问(答案是没鸟关系)。你要想搞个 array2 对象欢迎自己写一个。在这里叫破喉咙都没人把你当回事。

    还谈跨语言写结构。不同语言结构差远了。给你个 haskell 你不得喷这玩意怎么连循环都没有了。PHP 本来就是一个以值传递为主的语言,就算是对象变量也依然是传值的,只不过这个值是对象指针所以写起来会有传引用的效果。你要是起手就想把别的语言根基给整个掀了,我劝你还是回去写 Jaba 吧。

    这段逻辑,放在 Python 里是会用 list comprehension 写,放在 Ruby 里会用 block chain 写,放在 Jaba 里可以用 stream lambda 写,放在 PHP 里也只需要把追加数组项那行放在最后就行了。
    msg7086
        9
    msg7086  
       2021-12-18 12:47:34 +08:00 via Android
    > 后面会有 break 、return 等复杂逻辑,因此此处进行赋值代码量最少

    复杂逻辑不放进函数里?不封装进对象里? peer review 不会被同事骂死吗?
    xiangyuecn
        10
    xiangyuecn  
    OP
       2021-12-18 13:25:14 +08:00
    @msg7086 #9 同事已经拍桌子了,下一步应该要拿刀了😂

    “PHP 中的 array 实际上是一个有序映射。映射是一种把 values 关联到 keys 的类型。此类型针对多种不同用途进行了优化; 它可以被视为数组、列表(向量)、哈希表(映射的实现)、字典、集合、堆栈、队列等等。 由于 array 的值可以是其它 array 所以树形结构和多维 array 也是允许的。” 至少在很多地方,它讲的这一套东西叫法,更偏向对象😂

    新手:php 没有对象,只有数组(字典也叫数组)😂 ,等学到 class 了才有会发对象😂
    IvanLi127
        11
    IvanLi127  
       2021-12-18 13:47:48 +08:00
    楼主你使用冒号的方式好奇特……
    weirdo
        12
    weirdo  
       2021-12-18 15:56:21 +08:00
    哈哈哈 ,本来打了一大堆字,最后还是想了想,就说四个字,尊重祝福~
    landers2015
        13
    landers2015  
       2021-12-18 16:09:45 +08:00
    看了下楼主代码,一致同意、确定、一定是语言的问题
    seakingii
        14
    seakingii  
       2021-12-18 18:28:13 +08:00
    你竟敢说 PHP 语言不行?不想活了?
    msg7086
        15
    msg7086  
       2021-12-18 18:57:33 +08:00 via Android   ❤️ 1
    @xiangyuecn 我是从 PHP4 开始写起来的,那时候 PHP 对对象和类的支持还非常简陋原始,PHP 基本是一个面向过程语言(可以看作和 C 非常类似但大幅简化的语言),对象是一个非常小众,很少有人用到的 feature 。大概一直到 2007 年前后我才看到越来越多的项目开始用类结构来构建项目。你想想,像是 Zend framework 这种项目都是 2005 年才开始搞的。但是那时候主流的开发依然是面向过程。2009 年我在一家公司做架构设计,老大还跟我说不要把面向对象结构设计得太复杂,否则老员工玩不明白,于是只好自己写个 MVC 框架,只用了一点点面向对象设计,controller 依然做成了面向过程结构,满足老员工的复古风需求。

    PHP4 里的类结构连可见性控制都没有(即没有 private public 之分),没有接口 interface ,也没有引用传递。一直到后来 PHP5 里才加入这些新功能。只不过像是数组这种超大规模使用的特性,不可能说改就改的,这么多年下来的项目,兼容性不可能说砍就砍,毕竟有太多的地方依赖数组传值。
    xiangyuecn
        16
    xiangyuecn  
    OP
       2021-12-18 19:33:05 +08:00
    @msg7086 👍
    Wenco
        17
    Wenco  
       2021-12-18 22:05:53 +08:00
    后面‘$‘, ’->‘ 确实是个槽点,但也没办法,就跟语言定的关键字一样

    > 至少在很多地方,它讲的这一套东西叫法,更偏向对象😂

    更像数组和 hashmap 的结合体吧

    你强行把数组当对象用,然后还怪别人不支持,哪个语言都不支持吧。。。
    qeqv
        18
    qeqv  
       2021-12-18 22:47:29 +08:00
    PHP 的数组就是一种数据结构,见过一些老代码把数组当对象用的,弄了一个超大的数组,然后直接 return 或者给函数传参,导致内存占用疯涨。。。。
    另外学语言得搞清楚变量作用域,PHP 的变量只有全局作用域和函数作用域
    loginv2
        19
    loginv2  
       2021-12-19 09:52:09 +08:00
    感觉写$太难受了 所以直接 ahk 伺候了,三击 4 键输入$
    $4::
    if pressesCount > 0 ; > 0 说明 SetTimer 已经启动了,按键次数递增
    {
    pressesCount += 1
    return
    }
    ;否则,这是新一系列按键的首次按键。将计数设重置为 1 ,并启动定时器:
    pressesCount = 1
    SetTimer, WaitKey, 400 ;在 400 毫秒内等待更多的按键。
    return

    WaitKey:
    SetTimer, WaitKey, off
    if pressesCount = 1 ;该键已按过一次。
    {
    Gosub singleClick
    }

    else if pressesCount = 2 ;该键已按过两次。
    {
    Gosub doubleClick
    }

    else if pressesCount = 3
    {
    Gosub trebleClick
    }
    ;不论上面哪个动作被触发,将计数复位以备下一系列的按键:
    pressesCount = 0
    return

    singleClick:
    send 4
    return

    doubleClick:
    send 44
    return

    trebleClick:
    send $
    return
    charlie21
        20
    charlie21  
       2021-12-19 12:03:59 +08:00
    你不配用 PHP
    ivanfjz
        21
    ivanfjz  
       2021-12-19 13:25:05 +08:00
    你就狗屁不是~~
    limingxinleo
        22
    limingxinleo  
       2021-12-20 09:37:17 +08:00
    只看了标题,内容我都没看,我就已经得出结论了,

    这世界上没有适合你的语言!!!
    wowbaby
        23
    wowbaby  
       2021-12-20 09:58:10 +08:00
    我从没碰到过类似的问题,我怎么感觉代码执行没有问题啊,是你自己的问题吧?


    $list=array();
    for($i=0;$i<10;$i++){
    $obj=array();
    $list[]=$obj

    $obj["val"]=$i;
    }

    为什么要这么写,又不是对象,能这么写,我头一次看到这样的?

    应该是
    $obj=array();
    $obj["val"]=$i;
    $list[]=$obj;

    这样的顺序吧



    $list=array();
    for($i=0;$i<10;$i++){
    $obj=array(); // 这里已经重置了
    $list[]=&$obj;

    $obj["val"]=$i;
    }

    //list= [{val:9},{val:9},......,{val:9}]

    这段代码结果也没错啊,
    elevioux
        24
    elevioux  
       2021-12-20 10:25:38 +08:00
    list[]=obj ,为什么要先赋值到 list 先呢?
    obj 确定以后再赋值不就好了吗?也不用 unset ,引用啥的。
    也可以 list[i][val]=1 来操作 obj 。

    可能其他语言会有不同习惯,我一直写 php 都没留意。
    sanggao
        25
    sanggao  
       2021-12-20 10:57:40 +08:00
    php 这么亲民友好的语言,你都玩不明白,的确 狗屁不是
    Wenco
        26
    Wenco  
       2021-12-20 13:03:58 +08:00
    @elevioux

    > //后面会有 break 、return 等复杂逻辑,因此此处进行赋值代码量最少

    因为这个吧,他无法做到在最后一行将 obj 塞入 list ,又不想在每个跳出的地方重复写$list[] = $obj ,更不想优化自己的代码,所以只能吐槽 PHP 了
    JaguarJack
        27
    JaguarJack  
       2021-12-20 16:02:05 +08:00
    不应该直接
    ```php

    $list[] = array('val' => $i);

    ```
    一行就完事了。看了半天才缓过来
    NoahVI
        28
    NoahVI  
       2022-09-09 14:39:59 +08:00
    @msg7086 这个是大佬
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5395 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 06:56 · PVG 14:56 · LAX 22:56 · JFK 01:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.