default eye-catch image.

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

PSR-4の一次情報を読んだことだし、現在の理解でPSR-4 Autoloadに対応したクラスを作成し実際にAutoloadしてみる。composerもPSR-4に対応しているが、まずはPHP-Figがサンプルとして公開しているspl_autoloaderを使った例を試すことにする。 仕様は以下の通り。 Fully qualified class name ikutyexamplePsr4HelloWorld Namespace Prefix ikutyexamplePsr4 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 ikutyexamplePsr4; class HelloWorld { public function __construct() { echo \"Hello World!\"; } public function say() { echo \"Hello World!\"; } } 呼出側の作成(PSR-0的) PHP Figにあるクロージャ版spl_autoloaderを使った実装例を試してみる。 ikutyexamplePsr4HelloWorldを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 ikutyexamplePsr4HelloWorld(); 33 $example->say(); 名前空間プレフィックスとBaseDirectoryの紐づけは結局人力でやっている。「名前空間プレフィックス」と「クラス名」の間にある「サブ名前空間」を読み飛ばしている。名前空間プレフィックスに続く「サブ名前空間」分をクラス側が自由に使えるところが興味深い。 実行結果 実行してみる。実行結果から分かりにくくて恐縮だが、new()してもHello World!は出力されず、say()メソッドを実行したときにHello World!が2回表示された。late-binding的な感じ。 $ php sample.php Hello World!Hello World! 名前空間の深さと関係なくBaseDirectoryを設定する(PSR-4的) 例えば、ikutyexamplePsr4HelloWorldの名前空間プレフィックスikutyexamplePsr4をBaseDirectory ./ikuty-example-psr4 に紐づければ、名前空間がどれだけ深くてもデプロイは影響を受けない。 Fully qualified class name ikutyexamplePsr4HelloWorld Namespace Prefix ikutyexamplePsr4 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 ikutyexamplePsr4HelloWorld(); 35 $example->say(); 結論 PHP-Figがサンプルとして提供しているspl_autoloader(クロージャ版)をお試し実装してみた。 PSR-4は名前空間プレフィックスのベースディレクトリの関連を記述する仕様であり、ベースディレクトリの物理的な配置が名前空間プレフィックスに直接影響を受けない。 ベースディレクトリが深くならなくて良い

default eye-catch image.

PSR-4 の理解

What\'s PSR-4 ? そもそもPSRって何の略だろうと調べたがそこから出てこなかった。 ↓なんじゃないか、という意見あり。 PHP Standard Recommendation PHP Specification Request カテゴリ毎に数字が割り当てられており他にも以下が存在する。 PSR-0 Autoloading PSR-1 Basic Coding Standard PSR-2 Coding Style Guide PSR-3 Logger Interface PSR-4 Improved Autoloading PSR-6 Chaching Interface PSR-7 HTTP Message Interface PHP-FIGという団体で取りまとめられている。http://www.php-fig.org/ PSR-4 それでは早速一次情報から漁ってみる。どのパスにどのクラスを配置するのか仕様を決めたいというのが根っこにある。決まりがあればクラスを使う側が楽だから。楽に使ってもらえるよう配布手段に規約を設ける。PSR-0(等?)と互換性がある。(PSR-0以外にもこういう決まりがあるのか?) This PSR describes a specification for autoloading classes from file paths. It is fully interoperable, and can be used in addition to any other autoloading specification, including PSR-0. This PSR also describes where to place files that will be autoloaded according to the specification. 仕様 言葉遊び ドキュメント内では\"class\"は class,interfaces,traits,それに似た構造を指すそうだ。あくまでも外部から使用する対象と配置に関する仕様だよ、ということだ。対象は何でも良い。 The term \"class\" refers to classes, interfaces, traits, and other similar structures. 完全修飾クラス名 完全修飾クラス名は次のような形式となるそうだ。 A fully qualified class name has the following form: \<NamespaceName>(<SubNamespaceNames>)*<ClassName> いくつか決まり事がある。 The fully qualified class name MUST have a top-level namespace name, also known as a \"vendor namespace\". 完全修飾クラス名にはベンダーを表すユニークな名前空間が入っていないといけない。 NamespaceNameが一意なのか、NamespaceNameとSubNamespaceNamesの合わせ技で一意なのか不明。 GitHubに上がってるのを見るとNamespaceNameだけで表現しているようだ。「トップレベル」って「一番最初=NamespaceName」のことか?? The fully qualified class name MAY have one or more sub-namespace names. 補助的に名前空間を複数追加しても良い。 階層構造を持った複雑な名前空間も定義できるということ。 The fully qualified class name MUST have a terminating class name. 完全修飾クラス名の最後はクラス名でなければならない。 Underscores have no special meaning in any portion of the fully qualified class name. アンスコは特別な意味を持たない。 アンスコを前後の識別子の接続子のように使うフレームワークが多いからね。 アンスコは単なる文字。 Alphabetic characters in the fully qualified class name MAY be any combination of lower case and upper case. 大文字小文字の任意の組み合わせで良い。 大文字小文字に意味を持たせるフレームワークが多いからね。 All class names MUST be referenced in a case-sensitive fashion. 大文字小文字を区別する。 ファイルをロードする側の決まりごと A contiguous series of one or more leading namespace and sub-namespace names, not including the leading namespace separator, in the fully qualified class name (a \"namespace prefix\") corresponds to at least one \"base directory\". NamespaceNameといくつかのSubNamespaceNameを「名前空間プレフィックス」と呼ぶ SubNamespaceNameが複数個あった場合その全てが「名前空間プレフィックス」になるとは読めない。 完全修飾クラス名とは「名前空間プレフィックス」+(「サブ名前空間」)+「クラス名」となる。 「名前空間プレフィックス」がディレクトリ名と対応している必要がある。と書いてあるがサンプルの「BaseDirectory」が名前空間プレフィックスと全然違う。意味不明。 The contiguous sub-namespace names after the \"namespace prefix\" correspond to a subdirectory within a \"base directory\", in which the namespace separators represent directory separators. The subdirectory name MUST match the case of the sub-namespace names. 名前空間プレフィックスに続くサブ名前空間が、BaseDirectoryに続くサブディレクトリに対応する。 サブ名前空間とサブディレクトリの大文字小文字は一致している必要がある。 The terminating class name corresponds to a file name ending in .php. The file name MUST match the case of the terminating class name. 終端のクラス名は、大文字小文字が一致するphpファイルと対応する。 例 PSR-4の例。やはり、どうも規則性が見えない。 FULLY QUALIFIED CLASS NAME NAMESPACE PREFIX BASE DIRECTORY RESULTING FILE PATH AcmeLogWriterFile_Writer AcmeLogWriter ./acme-log-writer/lib/ ./acme-log-writer/lib/File_Writer.php AuraWebResponseStatus AuraWeb /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php SymfonyCoreRequest SymfonyCore ./vendor/Symfony/Core/ ./vendor/Symfony/Core/Request.php ZendAcl Zend /usr/includes/Zend/ /usr/includes/Zend/Acl.php 全然規則性が見えないぞ? 全然しっくりこないのでさらに調べてみた。COMPOSERがだいぶ前にPSR-4に対応したらしいのでAUTOLOADの補完ルールを色分けした。を参考にさせて頂きました。 FULLY QUALIFIED CLASS NAME NAMESPACE PREFIX BASE DIRECTORY RESULTING FILE PATH AcmeLogWriterFile_Writer AcmeLogWriter ./acme-log-writer/lib/ ./acme-log-writer/lib/File_Writer.php AuraWebResponseStatus AuraWeb /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php SymfonyCoreRequest SymfonyCore ./vendor/Symfony/Core/ ./vendor/Symfony/Core/Request.php ZendAcl Zend /usr/includes/Zend/ /usr/includes/Zend/Acl.php 訳にも書いたが、全てのサブ名前空間が名前空間プレフィックスに含まれる訳ではないことに注意。名前空間プレフィックスに含まれなかったサブ名前空間が突然ファイルパスに出現したりする。 サブ名前空間とBaseDirectoryの規則性について、サブ名前空間をハイフンで区切った一つのディレクトリと対応させる場合もあるし、階層構造まで一致させる場合もある。名前空間プレフィックスとBase Directoryの関係性は割と柔軟。