PHP で匿名クラスを new するときのカッコの位置がなんか変
◆ new class {}(); じゃなくて new class() {};
ある関数がオブジェクトを返して そのメソッドを呼び出したいです
かんたんに書くとこういう感じのものです
だけど class 定義はなくてわざわざそのために外部にクラス定義をしたくはないです
object にキャストすれば stdClass になるので それを使ってみます
JavaScript 感覚だとこれでいいのですが PHP はプロパティとメソッドを明確に分けて考えるので foo メソッドは定義されてなくてエラーになります
プロパティとして取り出してそれを関数として実行するという扱いなので () を入れてこうしないといけません
他に方法はないかと探すとそういえば new class {} で匿名クラスのインスタンスを作れました
外部にクラス定義をせずにその場に定義を書いてインスタンスを作成できます
これで動きます
ただ 実際にやりたいことだと + 1 のところで x の引数として受け取った値を使いたいです
としましたが これだとエラーです↓
Undefined variable $value
メソッド内から $value にアクセスできません
匿名クラスを使った場合もクロージャと同じで親スコープを見れないようです
use をつけたいところですが メソッドには use をつけれないようです
と書くとエラーです↓
syntax error, unexpected token "use", expecting ";" or "{"
調べたらインスタンスの作成時にコンストラクタへの引数として渡してプロパティとして保持するらしいです
納得はできますが 面倒です
とりあえず書いてみたら
エラーでした↓
syntax error, unexpected token "(", expecting ";"
何が悪いのか分からずドキュメントの例と比較すると () の位置が class キーワードの後にくるようです
これが正しい構文です
なぜそこに () が来るの?
扱いが use みたいなものだから それに合わせて先に書くようにしたのでしょうか?
知らずに見ると継承するのかなって思います
通常のインスタンス作成は
なので
という構文です
クラス定義は
で 匿名クラスならクラス名のところにクラス定義が入り クラス名の A はなくていいから省略するとして
になるのが自然です
JavaScript でもこの構文です
相変わらず PHP は言語の構文に一貫性がなくて 他の部分の構文から推測してこうなるだろうというのを外してきます
各所でそこ限定の特別な書き方になってます
基本だけ覚えたらあとは応用で 覚えて無くてもどうにかなるのが理想なのに全部覚えないといけないになるのは使いづらいです
こういうのが多いのが PHP の嫌なところなんですよね
かんたんに書くとこういう感じのものです
function x() {
// ...
return $obj;
}
x()->foo(1);
だけど class 定義はなくてわざわざそのために外部にクラス定義をしたくはないです
object にキャストすれば stdClass になるので それを使ってみます
function x() {
return (object)['foo' => function($arg) { return $arg + 1; }];
}
x()->foo(1);
JavaScript 感覚だとこれでいいのですが PHP はプロパティとメソッドを明確に分けて考えるので foo メソッドは定義されてなくてエラーになります
プロパティとして取り出してそれを関数として実行するという扱いなので () を入れてこうしないといけません
(x()->foo)(1);
他に方法はないかと探すとそういえば new class {} で匿名クラスのインスタンスを作れました
外部にクラス定義をせずにその場に定義を書いてインスタンスを作成できます
function x() {
return new class {
function foo($arg) {
return $arg + 1;
}
};
}
x()->foo(1);
// 2
これで動きます
ただ 実際にやりたいことだと + 1 のところで x の引数として受け取った値を使いたいです
function x($value) {
return new class {
function foo($arg) {
return $arg + $value;
}
};
}
x(1)->foo(1);
// 2
としましたが これだとエラーです↓
Undefined variable $value
メソッド内から $value にアクセスできません
匿名クラスを使った場合もクロージャと同じで親スコープを見れないようです
use をつけたいところですが メソッドには use をつけれないようです
new class {
function foo($arg) use ($value) {}
};
と書くとエラーです↓
syntax error, unexpected token "use", expecting ";" or "{"
調べたらインスタンスの作成時にコンストラクタへの引数として渡してプロパティとして保持するらしいです
納得はできますが 面倒です
とりあえず書いてみたら
function x($value) {
return new class {
function __construct($value) {
$this->value = $value;
}
function foo($arg) {
return $arg + $this->value;
}
}($value);
}
エラーでした↓
syntax error, unexpected token "(", expecting ";"
何が悪いのか分からずドキュメントの例と比較すると () の位置が class キーワードの後にくるようです
これが正しい構文です
function x($value) {
return new class ($value) {
function __construct($value) {
$this->value = $value;
}
function foo($arg) {
return $arg + $this->value;
}
};
}
なぜそこに () が来るの?
扱いが use みたいなものだから それに合わせて先に書くようにしたのでしょうか?
知らずに見ると継承するのかなって思います
通常のインスタンス作成は
new Class(1);
なので
new クラス名(引数);
という構文です
クラス定義は
class A {}
で 匿名クラスならクラス名のところにクラス定義が入り クラス名の A はなくていいから省略するとして
new class {}();
になるのが自然です
JavaScript でもこの構文です
相変わらず PHP は言語の構文に一貫性がなくて 他の部分の構文から推測してこうなるだろうというのを外してきます
各所でそこ限定の特別な書き方になってます
基本だけ覚えたらあとは応用で 覚えて無くてもどうにかなるのが理想なのに全部覚えないといけないになるのは使いづらいです
こういうのが多いのが PHP の嫌なところなんですよね