记录一个Yii神坑

只有想不到没有坑不了

惊心动魄

最近在写一个项目迭代,在慢慢跟之前的代码,陆陆续续的迭代。今天调一个页面的时候却出现了一个十分诡异的报错:

这十分不科学,相关代码不曾改动,测试环境也没有任何问题,而且本地跟测试是同一个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
2
3
4
$model->OK;

Unknown Property – yii\base\UnknownPropertyException
Getting unknown property: app\modules\survey\models\SurveyChoiceDistribution::OK

直接写属性,没有问题,$name是OK;

1
2
3
4
5
$OK = 'OK';
$model->$OK;

Unknown Property – yii\base\UnknownPropertyException
Getting unknown property: app\modules\survey\models\SurveyChoiceDistribution::OK

将OK赋予给一个字符串变量,$name还是OK;

1
2
3
4
5
$OKArr = ['OK'];
$model->$OKArr[0];

Unknown Property – yii\base\UnknownPropertyException
Getting unknown property: app\modules\survey\models\SurveyChoiceDistribution::Array

困扰我许久的Array出现了!!!Yii竟然是直接把$OKArr当做了属性,并没有解析$OKArr[0]。

思考

了解Yii的解析机制后,其实也明白了为何要怎么解析。$model->$OKArr[0]这个写法是有歧义的,可以理解为$model->($OKArr[0]),也可以理解为($model->$OKArr)[0]。(注意,这里的括号只是为了方便标识,实际上并没有这种写法)

而测试和线上之所以可以正常解析,可能是因为不同的Yii版本,这才是坑的地方。

在这里给大家一个建议,如果有这种数组场景,最好写成:

1
2
3
$OKArr = ['OK'];
$OK = OKArr[0];
$model->$OK;

这实际上就是强制先解析数组,将Yii可以解析的字符串写入->后。