只有想不到没有坑不了
惊心动魄
最近在写一个项目迭代,在慢慢跟之前的代码,陆陆续续的迭代。今天调一个页面的时候却出现了一个十分诡异的报错:
这十分不科学,相关代码不曾改动,测试环境也没有任何问题,而且本地跟测试是同一个docker环境…总之,要多诡异有多诡异。但没办法,错误它就是抛出来了,你得一一排查。
错误追踪
根据错误提示,第一个想到的就是验证$fieldsMap[array_keys($this->LEVEL_1_MAP)[$key]]究竟是不是数组:
1 | var_dump($fieldsMap[array_keys($this->LEVEL_1_MAP)[$key]]); |
这简直是年度最佳恐怖故事了,类型为string,没毛病,难道是model中没有这个属性?
1 | var_dump($model->__A0); |
还是没有任何毛病,于是把目光放到抛出错误的地方:
这不得不让我去思考,$name究竟是怎么解析获得的呢?
爬坑
接着做了几个case,来验证这个$name:
1 | $model->OK; |
直接写属性,没有问题,$name是OK;
1 | $OK = 'OK'; |
将OK赋予给一个字符串变量,$name还是OK;
1 | $OKArr = ['OK']; |
困扰我许久的Array出现了!!!Yii竟然是直接把$OKArr当做了属性,并没有解析$OKArr[0]。
思考
了解Yii的解析机制后,其实也明白了为何要怎么解析。$model->$OKArr[0]这个写法是有歧义的,可以理解为$model->($OKArr[0]),也可以理解为($model->$OKArr)[0]。(注意,这里的括号只是为了方便标识,实际上并没有这种写法)
而测试和线上之所以可以正常解析,可能是因为不同的Yii版本,这才是坑的地方。
在这里给大家一个建议,如果有这种数组场景,最好写成:
1 | $OKArr = ['OK']; |
这实际上就是强制先解析数组,将Yii可以解析的字符串写入->后。