環境
初書:2020/09/27
PC:macOS 10.15.7
php 7.4.10
前置き
PHPで可変変数を扱う時があったのだが、その時にかなり手こずったのでメモ。
前提
可変変数の知識
コード(失敗例)
class cls {
public string $str1;
public string $str2;
public function __construct(){
$this->str1 = "aa";
$this->str2 = "bb";
}
}
$ouc = new cls();
とりあえずクラスを用意して、インスタンスした。
そしてこの後、str変数にアクセスしたいのだが、この時に少し変わったことをする。
$arr[] = "str1";
$arr[] = "str2";
$ouc->$arr[0] = "cc";
何をしたいかというと、$arr[0]
= "str1"、つまり$ouc->str1 = "cc";
を行おうとした。
一見問題なく実行できそうだが、実はnoticeが発生する。
PHP Notice: Array to string conversion in php
これは配列を文字列として扱おうとした際に起こるエラーである。
だが、パッと見では特に不具合がある場所はない。
エラーの原因
原因自体は単純で、構文の解析方法が思っているのと違うということ。
PHP7以降の構文解析は、
$ouc->$arr[0] = "cc";
¯¯¯¯ // 1
¯¯¯¯¯¯¯¯¯¯¯¯¯ // 2
という順番になる。
つまり、$arr (=Array。配列なので)を先に返し、
$ouc->Array[0]
にcc
を代入しようとしたのである。(そして実際に代入した)
そのため、var_dump($ouc)
を行うと、
object(cls)#1 (3) {
["str1"]=>
string(2) "aa"
["str2"]=>
string(2) "bb"
["Array"]=>
array(1) {
[0]=>
string(2) "cc"
}
}
という形になる。
対処法
可変変数の別の記述方法である
$ouc->{$arr[0]} = "cc";
という風に、全体を{}
で括って正しい順番で解析してもらうか、一旦別の変数に置く。
終わりに
このバグに遭遇した場合、(構文解析の順番を知らない場合は)エラー文をみてもこれが原因だということに気付けない上に、エラー箇所より前の時点でログを出しても特に見つからない1ので(もちろん、あとでvar_dumpするとすぐにわかるのだが)、頭の片隅に入れておいてもいいかもしれない。
参考サイト
-
$arr[0]
単体でechoしても、cls
をvar_dumpしても気付かないし、issetしても…falseになるから気付くかもしれない。自分はエラーに気を取られて戻り値が来ている事に気付いてなかった。 ↩