PHP の名前空間が残念仕様だった
◆ やっぱり PHP クオリティです
PHP にはいつのころからか 名前空間機能ができました
でも もともとはないものだったのでなくてもそこまで困りません
大きなものを作るときなら あったほうがいいかもしれません
インナークラスも作れないので名前衝突可能性が高くなりますし
ただ私の場合はちょっとしたスクリプトで node.js より PHP のほうが楽そうなときに使うことばかりで いわば shell script 代わりです
なのでこれまで名前空間はほぼ使ったことはありませんでした
C# だと .NET Framework の組み込みのライブラリが名前空間で管理されてるので意識する必要があります
C# の影響もあってなんとなく PHP で名前空間使ってみようとしたら C# とは違う微妙な仕様でした
namaespace という名前空間にクラスと enum を定義します
[a.cs]
別の名前空間 app のプログラムからこれらを参照します
[b.cs]
名前空間もつけてクラス名や enum 名をかけば参照できます
毎回書くのは面倒なので using を使うとこう書けます
[c.cs]
using で namaespace を指定しているので namaespace にあるものは直接書くことができます
[a.php]
[b1.php]
[b2.php]
b と言う名前空間に B1 と B2 クラスがあります
a と言う名前空間で use \b を指定しています
PHP では \ が名前空間の区切り文字でパスの / みたいなものです
\b はルートの b を表すことになります
a.php を実行すると一見何も問題なさそうですが
a\B1 はありませんと言うエラーになります
b\B1 ではなく 名前空間 a を見ています
クラスを参照するところをちょっと変えてみます
[a.php]
これだとエラーなしです
これから 「use \b」 をなくすと
a 名前空間の中から b\B1 を探そうとしています
use \b があると b 空間から探しているのでエラーなくみつけることができています
ということからわかるように PHP の use は指定した名前空間の中のクラスなどを直接読み込めるようにしてくれるものではありません
単純にエイリアスというだけです
シンプルな 1 階層なので
[b.php]
[a.php]
k\B1 だけで済みます
でも やっぱり 「k」 邪魔です
なんで C# みたいなものにしなかったんだろう
use してるんだからその名前空間ものはプレフィックスなしに書けるようにしてほしいです
関数も use があるかどうかで 標準に存在する関数か自作を切り替えれるようになってほしいです
例えば array_map(~); と書いていても use ~; って入れるだけで PHP の関数からその名前空間にある関数になって動きを変えれるとか
use いっぱいすると名前被る可能性もありますが それなら被る場合にだけ プレフィックス付きにすればいいと思います
PHP は PHP だなぁ と思える仕様でした
でも もともとはないものだったのでなくてもそこまで困りません
大きなものを作るときなら あったほうがいいかもしれません
インナークラスも作れないので名前衝突可能性が高くなりますし
ただ私の場合はちょっとしたスクリプトで node.js より PHP のほうが楽そうなときに使うことばかりで いわば shell script 代わりです
なのでこれまで名前空間はほぼ使ったことはありませんでした
C# だと .NET Framework の組み込みのライブラリが名前空間で管理されてるので意識する必要があります
C# の影響もあってなんとなく PHP で名前空間使ってみようとしたら C# とは違う微妙な仕様でした
C# の場合
まずは C# の場合ですnamaespace という名前空間にクラスと enum を定義します
[a.cs]
namespace namaespace
{
public class C1 { }
public class C2 { }
public enum E { e }
}
{
public class C1 { }
public class C2 { }
public enum E { e }
}
別の名前空間 app のプログラムからこれらを参照します
[b.cs]
namespace app
{
public class Program
{
public static void main()
{
new namaespace.C1();
new namaespace.C2();
var e = namaespace.E.e;
}
}
}
{
public class Program
{
public static void main()
{
new namaespace.C1();
new namaespace.C2();
var e = namaespace.E.e;
}
}
}
名前空間もつけてクラス名や enum 名をかけば参照できます
毎回書くのは面倒なので using を使うとこう書けます
[c.cs]
using namaespace;
namespace app
{
public class Program2
{
public static void main()
{
new C1();
new C2();
var e = E.e;
}
}
}
namespace app
{
public class Program2
{
public static void main()
{
new C1();
new C2();
var e = E.e;
}
}
}
using で namaespace を指定しているので namaespace にあるものは直接書くことができます
PHP の場合
[a.php]
<?php
namespace a;
use \b;
require "b1.php";
require "b2.php";
$b1 = new B1();
$b2 = new B2();
namespace a;
use \b;
require "b1.php";
require "b2.php";
$b1 = new B1();
$b2 = new B2();
[b1.php]
<?php
namespace b;
class B1 { }
namespace b;
class B1 { }
[b2.php]
<?php
namespace b;
class B2 { }
namespace b;
class B2 { }
b と言う名前空間に B1 と B2 クラスがあります
a と言う名前空間で use \b を指定しています
PHP では \ が名前空間の区切り文字でパスの / みたいなものです
\b はルートの b を表すことになります
a.php を実行すると一見何も問題なさそうですが
Fatal error: Uncaught Error: Class 'a\B1' not found in C:\code\phpns\a.php on line 9
Error: Class 'a\B1' not found in C:\code\phpns\a.php on line 9
Call Stack:
0.0003 353976 1. {main}() C:\code\phpns\a.php:0
PHP Fatal error: Uncaught Error: Class 'a\B1' not found in C:\code\phpns\a.php:9
Stack trace:
#0 {main}
thrown in C:\code\phpns\a.php on line 9
終了コード: 255
Error: Class 'a\B1' not found in C:\code\phpns\a.php on line 9
Call Stack:
0.0003 353976 1. {main}() C:\code\phpns\a.php:0
PHP Fatal error: Uncaught Error: Class 'a\B1' not found in C:\code\phpns\a.php:9
Stack trace:
#0 {main}
thrown in C:\code\phpns\a.php on line 9
終了コード: 255
a\B1 はありませんと言うエラーになります
b\B1 ではなく 名前空間 a を見ています
クラスを参照するところをちょっと変えてみます
[a.php]
<?php
namespace a;
use \b;
require "b1.php";
require "b2.php";
$b1 = new b\B1();
$b2 = new b\B2();
namespace a;
use \b;
require "b1.php";
require "b2.php";
$b1 = new b\B1();
$b2 = new b\B2();
これだとエラーなしです
これから 「use \b」 をなくすと
Uncaught Error: Class 'a\b\B1' not found
a 名前空間の中から b\B1 を探そうとしています
use \b があると b 空間から探しているのでエラーなくみつけることができています
ということからわかるように PHP の use は指定した名前空間の中のクラスなどを直接読み込めるようにしてくれるものではありません
単純にエイリアスというだけです
シンプルな 1 階層なので
new \b\B1();
かuse \b;
new b\B1();
でほぼ違いがなかったのですが 名前空間が深くなると必要性がでてきますnew b\B1();
[b.php]
<?php
namespace b\c\d\e\f\g\h\i\j\k;
class B1 { }
namespace b\c\d\e\f\g\h\i\j\k;
class B1 { }
[a.php]
<?php
namespace a;
use \b\c\d\e\f\g\h\i\j\k;
require "b1.php";
$b1 = new k\B1();
namespace a;
use \b\c\d\e\f\g\h\i\j\k;
require "b1.php";
$b1 = new k\B1();
k\B1 だけで済みます
でも やっぱり 「k」 邪魔です
なんで C# みたいなものにしなかったんだろう
use してるんだからその名前空間ものはプレフィックスなしに書けるようにしてほしいです
関数も use があるかどうかで 標準に存在する関数か自作を切り替えれるようになってほしいです
例えば array_map(~); と書いていても use ~; って入れるだけで PHP の関数からその名前空間にある関数になって動きを変えれるとか
use いっぱいすると名前被る可能性もありますが それなら被る場合にだけ プレフィックス付きにすればいいと思います
PHP は PHP だなぁ と思える仕様でした
COMMENT
コメント一覧 (1)
-
- 2017/06/10 10:59
-
> 被る場合にだけ プレフィックス付きにすればいい
場当たり的な対応ではなく、常に適用するのが基本では無いでしょうか?
> use してるんだからその名前空間ものはプレフィックスなしに
異なる名前空間のモノを使うのだから、『別の名前空間』である事を常に明確にしておく必要があると思います。
名前の重複がある場合に、(多分先頭にあるはずだが、インクルードしている別ファイルにあるかもしれない)use をチェックしてからじゃないと実体がどこにあるかを判別するのが難しいと思います。
インポートされていれば(その部分が見つかれば)解決は早いですが、同一名前空間内のモノである事を確定するには『全ての』関連ファイルをチェックする必要がありませんか?
(IDE を使っていれば、お任せできますが...)