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を以下の通り作成する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$ 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的なサンプル。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
[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的な感じ。
1 2 3 |
$ 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 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?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は名前空間プレフィックスのベースディレクトリの関連を記述する仕様であり、ベースディレクトリの物理的な配置が名前空間プレフィックスに直接影響を受けない。
- ベースディレクトリが深くならなくて良い