PSR-4の一次情報を読んだことだし、現在の理解でPSR-4 Autoloadに対応したクラスを作成し実際にAutoloadしてみる。composerもPSR-4に対応しているが、まずはPHP-Figがサンプルとして公開しているspl_autoloaderを使った例を試すことにする。
仕様は以下の通り。
| Fully qualified class name | \ikuty\example\Psr4\HelloWorld |
|---|---|
| Namespace Prefix | \ikuty\example\Psr4 |
| Base Directory | ./src/ikuty/example/Psr4 |
| Resulting file path | ./src/ikuty/example/Psr4/helloworld.php |
サンプルクラスの作成
./src/ikuty/example/Psr4/helloworld.phpを以下の通り作成する。
$ pwd
./src/ikuty/example/Psr4
vi helloworld.php
<?php
namespace ikuty\example\Psr4;
class HelloWorld
{
public function __construct()
{
echo "Hello World!";
}
public function say()
{
echo "Hello World!";
}
}
呼出側の作成(PSR-0的)
PHP Figにあるクロージャ版spl_autoloaderを使った実装例を試してみる。
\ikuty\example\Psr4\HelloWorldをnew()すると、spl_autoload_registerで登録したクロージャが評価される。
なお、名前空間の深さとBaseDirectoryの深さ等しくしている意味でPSR-0的なサンプル。
[sample.php]
<?php
2 spl_autoload_register(function ($class){
3
4 //project-specific namespace prefix
5 $prefix = 'ikuty\\example\\Psr4\\';
6
7 //base directory for the namespace prefix
8 $base_dir = __DIR__ . '/src/ikuty/example/Psr4/';
9
10 //does the class use the namespace prefix?
11 $len = strlen($prefix);
12 if (strncmp($prefix, $class, $len) !== 0){
13 // no, move to the next registerd autoloader
14 return;
15 }
16
17 //get the relative class name
18 $relative_class = substr($class, $len);
19
20 //replace the namespace prefix with the base directory, replace namespace
21 //separators with directory separators in the relative class name, append
22 //with .php
23 $file = $base_dir . str_replace('\\','/', $relative_class).'.php';
24
25 //if the file exists, require it
26 if (file_exists($file)) {
27 require $file;
28 }
29
30 });
31
32 $example = new \ikuty\example\Psr4\HelloWorld();
33 $example->say();
名前空間プレフィックスとBaseDirectoryの紐づけは結局人力でやっている。「名前空間プレフィックス」と「クラス名」の間にある「サブ名前空間」を読み飛ばしている。名前空間プレフィックスに続く「サブ名前空間」分をクラス側が自由に使えるところが興味深い。
実行結果
実行してみる。実行結果から分かりにくくて恐縮だが、new()してもHello World!は出力されず、say()メソッドを実行したときにHello World!が2回表示された。late-binding的な感じ。
$ php sample.php
Hello World!Hello World!
名前空間の深さと関係なくBaseDirectoryを設定する(PSR-4的)
例えば、\ikuty\example\Psr4\HelloWorldの名前空間プレフィックス\ikuty\example\Psr4をBaseDirectory ./ikuty-example-psr4 に紐づければ、名前空間がどれだけ深くてもデプロイは影響を受けない。
| Fully qualified class name | \ikuty\example\Psr4\HelloWorld |
|---|---|
| Namespace Prefix | \ikuty\example\Psr4 |
| Base Directory | ./src/ikuty-example-Psr4 |
| Resulting file path | ./src/ikuty-example-Psr4/helloworld.php |
<?php
2 spl_autoload_register(function ($class){
3
4 //project-specific namespace prefix
5 $prefix = 'ikuty\\example\\Psr4\\';
6
7 //base directory for the namespace prefix
8 //$base_dir = __DIR__ . '/src/ikuty/example/Psr4/';
9 $base_dir = __DIR__ . '/src-ikuty-example-psr4/';
10
11
12 //does the class use the namespace prefix?
13 $len = strlen($prefix);
14 if (strncmp($prefix, $class, $len) !== 0){
15 // no, move to the next registerd autoloader
16 return;
17 }
18
19 //get the relative class name
20 $relative_class = substr($class, $len);
21
22 //replace the namespace prefix with the base directory, replace namespace
23 //separators with directory separators in the relative class name, append
24 //with .php
25 $file = $base_dir . str_replace('\\','/', $relative_class).'.php';
26
27 //if the file exists, require it
28 if (file_exists($file)) {
29 require $file;
30 }
31
32 });
33
34 $example = new \ikuty\example\Psr4\HelloWorld();
35 $example->say();
結論
- PHP-Figがサンプルとして提供しているspl_autoloader(クロージャ版)をお試し実装してみた。
- PSR-4は名前空間プレフィックスのベースディレクトリの関連を記述する仕様であり、ベースディレクトリの物理的な配置が名前空間プレフィックスに直接影響を受けない。
- ベースディレクトリが深くならなくて良い