PHP 設計

実践 PSR-4 クラスをspl_autoloaderを使ってautoloadしてみる最も簡単なサンプル

投稿日:

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は名前空間プレフィックスのベースディレクトリの関連を記述する仕様であり、ベースディレクトリの物理的な配置が名前空間プレフィックスに直接影響を受けない。
  • ベースディレクトリが深くならなくて良い

-PHP, 設計
-,

Copyright© ikuty.com , 2018 AllRights Reserved Powered by AFFINGER4.