[吐槽] PHP :哪天没有写 bug,算我输。数组哪里都是值拷贝;引用:蛋疼。明明是语言问题,硬说是我太菜 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xiangyuecn
V2EX    PHP

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

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

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

    //常规脑回路,写的代码,抱歉了,bug 成堆 $list=array(); for($i=0;$<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
    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 了
    akagishigeru
        27
    akagishigeru  
       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     Solana     871 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 21:10 PVG 05:10 LAX 14:10 JFK 17:10
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86