質問: new MyService(); ``` **引用元** 「PHPフレームワーク Laravel実践開発」 著者: 掌田津耶乃 MyServiceクラスの`$myservice`にインスタンスがすでに保存されていたらそれを返し、nullならnewしたインスタンスを代入。 **質問内容** `??`の右側にある`self::$myservice`を返すものだと認識しているのですが、必ず`new MyService()`が代入され、新しいインスタンスが返ってくるのではないか(インスタンスがすでにある場合も上書きされる)という点です。 ご教授ください。
回答: `??` 演算子は「Null 合体演算子 (Null Coalescing Operator)」です。`a ?? b` と書いたとき、これは `a` が `NULL` なら `b` と評価され、それ以外の場合は `a` と評価されます。詳しくはこちらにマニュアルがあります。 今回の例では、`??` 演算子に加え、「代入も式である」という PHP の性質が使われています。今回のプログラムに括弧を補うと、以下のようになります(※)。 ``` return (self::$myservice ?? (self::$myservice = new MyService())); ``` つまり、全体の挙動としてはこうなります: * `self::$myservice` が `NULL` でなければそれをそのまま `return` する。 * `self::$myservice` が `NULL` であれば、`self::$myservice` に `new MyService()` を代入した上で、その代入された値を `return` する。 (※) これは重箱の隅をつつく補足です:通常このような括弧の付け方を考える際は演算子の優先順位から考えます。「掛け算は足し算より優先順位が高いから `1 + (2 * 3)`」みたいな感じです。しかし今回の場合、演算子の優先順位から真面目に考えると代入演算子 `=` は NULL 合体演算子 `??` より優先順位が低いのでこんな括弧の付け方にはなりません。実は代入演算子だけは特別扱いされており、こう括弧を付けたような振る舞いをします。変です。 > > 注意: > > > `=` は他のほとんどの演算子よりも優先順位が低いはずなのにもかかわらず、 PHP は依然として `if (!$a = foo())` のような式も許します。この場合は `foo()` の返り値が `$a` に代入されます。 > > > おまけ1:このような記号だけからなる演算子の意味を知りたいときは、記号を説明する英語で検索すると良い感じにひっかかります。今回だと「PHP double question mark」で検索すると解説ページが出てきます。 おまけ2:ところでこのソースコードでは `self::$myservice` というのを 2 回書いており、面倒くさいですし typo にも繋がります。この問題を解決するため(この回答を書いている時点ではまだリリースされていませんが)PHP 7.4 からは `??=` という演算子が使えるようになります。