Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

5分で分かる名前空間とオートロード

32,888 views

Published on

第一回関西PHP初心者勉強会LTの元ネタです。

Published in: Technology
  • Be the first to comment

5分で分かる名前空間とオートロード

  1. 1. 5分で分かるかもしれない名前空間とオートロード 第1回 関西PHP初心者勉強会 2011年8月27日(土) スーパーグローバル世代のPHPer k-holy
  2. 2. 名前空間とは「ソースコード上で冗長な命名規則を用いなくても名前の衝突が起こらないようにし、しかもそれを容易に記述できるようにする」(Wikipediaより引用)ための概念PHP的には、名前の衝突を避けるために使われてきたPEAR命名規則、「HTTP_Request2_Adapter_Socket」のような、アンダースコア区切りの長いクラス名を整理し、適切に階層管理するための機能PHP5.3.0から利用可能
  3. 3. 名前空間を宣言するnamespace宣言は必ずコードの先頭に記述すること。(コメント、改行、スペースは宣言の前に書いてもよい)名前空間は「」(バックスラッシュ)区切りで階層を構成できる。<?phpnamespace HolyExample; //名前空間 ”HolyExample” を宣言※1ファイル内では1つの名前空間で完結させることを推奨
  4. 4. 名前空間を宣言するnamespace宣言は必ずコードの先頭に記述すること。(コメント、改行、スペースは宣言の前に書いてもよい)名前空間は「」(バックスラッシュ)区切りで階層を構成できる。<?phpnamespace HolyExample; //名前空間 ”HolyExample” を宣言ちなみに、誤っていわゆるBOM付UTF-8でファイルを保存したところ、こんなエラーで怒られてしまいました。Fatal error: Namespace declaration statement has tobe the very first statement in the script※BOM付きUTF-8には気をつけて!
  5. 5. 名前空間でのクラス定義名前空間で定義されるクラス/関数/定数は、先頭に名前空間を付加したものとして解釈される。namespace HolyExample;//名前空間”HolyExample”を宣言class Foo { //Fooクラスを定義 public static function getClass() { return __CLASS__;//クラス名を返す }}echo Foo::getClass();//HolyExampleFoo
  6. 6. 名前空間とグローバル空間PHPの定義済みクラス/関数/定数は、グローバル空間に配置される。名前空間でグローバル空間のクラスを使用する場合は、先頭に名前空間セパレータを付ける必要がある。関数や定数は、名前が被らない場合に限り従来通りの記述で構わない。逆に言うと、実は同名で定義すれば上書き可能(一部の定数を除く)namespace HolyExample;class Exception extends Exception{}$ns_ex = new Exception();//HolyExampleException$global_ex = new Exception();//ExceptionPHP_VERSION;//付けてもPHP_VERSION;//付けなくても同じ
  7. 7. 別の名前空間のクラスを使う別の名前空間に定義されたクラスを利用する場合、以下いずれかの方法で記述する。● 完全修飾名で記述● use 文でインポートしたクラス名で記述● use 文 + as キーワードで定義したエイリアスで記述
  8. 8. 完全修飾名名前空間セパレータを含む識別子のうち、先頭に名前空間セパレータを付けて指定したものを 完全修飾名 と呼ぶ。HolyExample名前空間で、ZendFramework2のZendOAuthConsumer クラスを使う場合の例● 完全修飾名 namespace HolyExample; //ZendOAuthConsumerクラスを完全修飾名で指定 $consumer = new ZendOAuthConsumer();※ファイルシステムでにおける絶対パスのようなもの
  9. 9. インポートとエイリアス● インポート namespace HolyExample; use ZendOAuthConsumer; //インポートしたクラス名 Consumer でアクセスできる $consumer = new Consumer();● エイリアス namespace HolyExample; use ZendOAuthConsumer as OAuthConsumer; //定義したエイリアス OAuthConsumer でアクセスできる $consumer = new OAuthConsumer();※適切なクラス名を付けていれば基本的にはインポートのみで良いはず
  10. 10. 更に詳しく知りたい方は PHP Manualで FAQもあります
  11. 11. オートロードとはクラスを利用する際、自動的にそのクラスが定義されているファイルを読み込む機能。(require_onceが不要に)spl_autoload_register()関数で、オートローダのコールバックを登録することで実装できる。spl_autoload_register(function ($className) { //「_」をディレクトリ区切り文字に置換してinclude return (bool)@include str_replace(_, DIRECTORY_SEPARATOR, $className) . .php;}, true, true);無名関数のこんな実装でも一応動くけど、これでは名前空間に対応できていないので…
  12. 12. PSR-0という規格オートローダの相互運用性を確保するために、クラスの完全修飾名とファイル名の命名規則として提案されている規格PSR-0 Final Proposal - PHP Standards Working Group – 2009-11-14http://bit.ly/8UPl4A※Symfony, Doctrine, ZendFramework, Lithium等の主要なPHP5.3以降専用フレームワークが対応この仕様に従って作成しておけば、おおむね問題なし
  13. 13. PSR-0の仕様重要なのはこの3点1.必ずトップレベルに「ベンダー名」を持たせ、完全修飾名を 「<ベンダー名>(<名前空間>)*<クラス名>」とする2.名前空間セパレータは DIRECTORY_SEPARATOR に変換される3.クラス名に含まれるアンダースコアは DIRECTORY_SEPARATOR に変換されるZendOAuthConsumer クラス(ベンダー名:Zend)→/project/lib/vendor/Zend/OAuth/Consumer.php※実装例の SplClassLoader はgistに掲載されているhttps://gist.github.com/221634
  14. 14. +αのオートローダ仕様PSR-0準拠は最低条件として、こんな仕様も追加しました。ベンダー名ごとに検索対象ディレクトリおよびファイル拡張子を指定可能とする● 架空のクラス Smorty の例 HolyLoader::getInstance() ->set(Smorty,//ベンダー名 /project/lib/vendor/Smorty/libs,//ディレクトリ .class.php)//拡張子 ->enableAutoload(); $smorty = new Smorty();//Smorty →/project/lib/vendor/Smorty/libs/Smorty.class.php
  15. 15. stream_resolve_include_path オートロードが呼ばれると、 コールバックオートローダの引 数にクラス名が完全修飾名で渡 されるので、PSR-0の仕様に 従ってファイルパスに変換し、 インクルードパスを考慮しつつ ファイルを検索する必要があり ます。 そこで役に立ったのが、この関 数 これ使えば、もう @include とか 書かなくてもいい ※PHP5.3.2以降
  16. 16. オートロード こんな時に呼ばれるnamespace HolyExample;//クラスのインスタンスを生成$foo = new Foo(); //HolyExampleFoo//スタティックメソッドをコール$foo = Foo::getClass();//クラス定数を記述Foo::CONSTANT;//クラス/インタフェース定義で extends, implementsclass RuntimeException extends RuntimeException //RuntimeException implements Exception {} //HolyExampleException
  17. 17. オートロード こんな時に呼ばれるnamespace HolyExample;//スタティックメソッドのコールバックを呼ぶcall_user_func(array(HolyExampleFoo, getClass));//class_exists(), interface_exists()で第2引数を指定しない、またはtrueを指定if (class_exists(HolyExampleFoo))※動的にクラス名を指定する際は完全修飾名で書かないとダメ
  18. 18. オートロード こんな時には呼ばれないnamespace HolyExample;//タイプヒンティングpublic function setFoo(Foo $foo)//HolyExampleFoo//instanceof演算子if ($foo instanceof Foo)//HolyExampleFoo//try-catch節try {} catch (Exception $e) {//HolyExampleException}
  19. 19. オートロード こんな時には呼ばれないnamespace HolyExample;//is_a(), is_subclass_of()if (is_a($foo, HolyExampleFoo))//スタティックメソッドのコールバックをis_callable()if (is_callable(array(HolyExampleFoo, getClass))//普通にis_callable()のエラーにはなる//class_exists(), interface_exists()で第2引数にfalseを指定if (class_exists(HolyExampleFoo, false))※動的にクラス名を指定する際は完全修飾名で書かないとダメ
  20. 20. オートロードが呼ばれないと…try { //UnknownExceptionがスローされるかもしれない処理} catch (UnkomanException $e) {//タイプミスしてる mail(dev@example.com, Unknown error, $e->getMessage());}例外がスローされた時にメールで通知するつもりが…Fatal error: Uncaught exceptionHolyExampleUnknownException with message...※そもそもこういう場当たり的な例外処理は避けた方が無難ですが
  21. 21. オートロードスタックspl_autoload_register()で複数のオートローダを登録した場合、オートロードが呼ばれたら、対象のクラスが定義されたファイルを読み込むまで、登録された順番で実行される。spl_autoload_register()の第3引数にTRUEを指定すると、スタックの末尾ではなく先頭に追加できるので、複数のオートローダを利用する場合は優先順位で使い分けが可能。spl_autoload_functions()でオートロードスタックの配列を取得できるので、オートロードの処理で何かがおかしい時はこれで確認してみてください。
  22. 22. まとめ● 名前空間は普通に使うだけなら難しくない● BOM付きUTF-8の罠には要注意● 名前空間/クラス名とファイルパスの対応はPSR-0を参考に● try-catchやinstanceofで例外を扱う時はオートロードが 呼ばれないのでtypoに気をつけて拙作オートローダのコードはgistに掲載しています。https://gist.github.com/1127033ありがとうございました。

×