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

2021-12-18 05:43:18 +08:00
 xiangyuecn

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

//常规脑回路,写的代码,抱歉了,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 代码:满屏的毫无意义的 $,满屏的毫无意义的两个字宽度的 -> ,代码看起来很肥 很保暖。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

更像数组和 hashmap 的结合体吧

你强行把数组当对象用,然后还怪别人不支持,哪个语言都不支持吧。。。
qeqv
2021-12-18 22:47:29 +08:00
PHP 的数组就是一种数据结构,见过一些老代码把数组当对象用的,弄了一个超大的数组,然后直接 return 或者给函数传参,导致内存占用疯涨。。。。
另外学语言得搞清楚变量作用域,PHP 的变量只有全局作用域和函数作用域
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
2021-12-19 12:03:59 +08:00
你不配用 PHP

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/822937

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX