ちょっと何言ってるのかわからない。
関数内関数
function foo(){
echo 'foo';
function bar(){
echo 'bar';
}
}
foo(); // foo
bar(); // bar ← !?
マジかよ。
実はしっかりマニュアルにも書かれている仕様です。
仕様ではあるのですが、つい先日までこの文法を知らなかったので、初めて見たとき面食らいました。
そもそもPHPで関数内に関数を書くという発想がなかったからということもありますが、普通はこれ関数内に閉じこもるでしょう。
function foo(){
console.log('foo');
function bar(){
console.log('bar');
}
}
foo(); // foo
bar(); // bar is not defined
一手加えるだけでクロージャになるやつだ。
ではPHPではクロージャができないのかというともちろんできます。
function foo(){
echo 'foo';
return function(){
echo 'bar';
}
}
$foo = foo(); // foo
$foo(); // bar
関数内の関数をreturnすることで、クロージャとして使えるようになります。
外側の値を使うにはuseが必要でJavaScriptより少しだけ面倒ですが。
でも私がこれを書くことになったとしたら、たぶんこう書きます。
class foo{
public function __construct(){
echo 'foo';
}
public function bar(){
echo 'bar';
}
}
$foo = new foo(); // foo
$foo->bar(); // bar
クラスのなかったJavaScriptでクロージャが発展したのはわからないでもないですが、PHPにクロージャがあって何が嬉しいのか、未だによくわかりません。
そもそもPHPのクロージャってClosureクラスですし。
クロージャがなければこれができなかった!みたいなのって何かあるんですかね?
まあ無名関数はarray_mapとかで時々使うんですが、マニュアルには『無名関数はクロージャとも呼ばれ』とか書いてあるんだけど別物だよね???
$foo = function(){
echo 'foo';
};
$foo(); // foo
関数内変数
これは当然グローバル展開されません。
function foo(){
$bar = 1;
}
foo();
echo $bar; // Undefined variable: bar
変数は見えないのに関数は外に出る。
なぜなのか。
…はて、そういえば変数以外はどうなるんだ?
関数内クラス
function declareClass(int $id){
if($id===1){
class HOGE{
public function __construct(){echo '$idは1';}
}
}else{
class HOGE{
public function __construct(){echo '$idは1以外';}
}
}
}
declareClass(1);
new HOGE(); // $idは1
declareClass(2); // 1ファイル内で書くとCannot declare classになる
new HOGE(); // $idは1以外
クラスもグローバルになるようです。
つまり、これを使えばDIできるというわけですね(できない)。
関数内インターフェイス、トレイト
function foo(int $id){
if($id===1){
interface HOGE{
const bar = 1;
}
trait FUGA{
public function baz(){
return 1;
}
}
}else{
interface HOGE{
const bar = 2;
}
trait FUGA{
public function baz(){
return 2;
}
}
}
}
foo(2);
class HOGE2 implements HOGE{
use FUGA;
}
$a = new HOGE2();
echo $a::bar, $a->baz(); // 2,2
foo(1)
としたら$a::bar
も$a->baz()
も1になります。
traitやinterfaceもグローバルに展開されるようです。
つまり、関数の中身は基本的にグローバルなんだけど、変数だけわざわざ関数外から見えないようにされているだけ、ということのようです。
なんだか元々関数に抱いていたイメージと全く逆なかんじの実装になっていました。