WebエンジニアのLoL日記

LoLをプレイしたりLJLの試合を見たりするのが好きなエンジニア。LoLのイベントやパッチノートなど気になった点を記事にしたり、LJLについの記事をかいたりしています。某社でWeb系のエンジニアとして働いているので、技術系の記事もたまに書きます。コンタクトを取りたい場合はtwitterまで。

PHPのcallableとその呼び方とクラスプロパティについて

f:id:yoshiki_utakata:20181004212834j:plain

先日、こんな事件がありました。

<?php

class Hoge
  public function doSomething() {
    $func = $this->func;
    $func();
    // これ以降 $func は使われていない
  }
}

このようなコードがあり、これを

<?php

class Hoge
  public function doSomething() {
    $this->func();
  }
}

こう書き換えた結果事故った。という事件がありました。

どういうことなのか

一見正しく変更したように見えるコードですが、何がだめなんでしょう。

$func = $this->func;
$func()

これが

$this->func()

こうなっただけです。なんか下の書き方も正しそうに見えますよね?

もっとわかりやすく

こうです

$this->func = function() {
  echo 'やったぜ';
}
$func = $this->func;
$func();

これの結果はどうなるでしょう?

当然「やったぜ」になります。

では

$this->func = function() {
  echo 'やったぜ';
}
$this->func();

これは?

「やったぜ」になりそうな気がしません。

何が間違いなの?

正しくはこうです

$this->func = function() {
  echo 'やったぜ';
}
($this->func)();

何が違うのでしょう。

具体的に動くコードで見てみる

PHPのPropertyとCallable *1

わかりましたか?

つまり、 $this->func() は クラスに実装されたメソッドを呼ぶというコードになるのです。

クラスのプロパティを呼ぶのは $this->func で、そのプロパティが callable な場合は ($this->func)() として、さきにプロパティとして解決させてあげてから、それをcallableとして呼ぶ、というように書く必要があるのです。

実はこの ($this->func)() という書き方、PHP7から使えるようになりました。PHP7以前は、最初に書いたように

$func = $this->func;
$func();

と一回変数に置く書き方でしか呼べないので、このコードは正しかったわけです。

PHP7になり Type Hinting 等便利な機能が多数つきましたが、地味にこういう機能もついてたんでしたね。へー。

*1:gistの貼り付け機能をはじめて使ってみた気がする