Se ha denunciado esta presentación.
Se está descargando tu SlideShare. ×

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

Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Cargando en…3
×

Eche un vistazo a continuación

1 de 22 Anuncio

Más Contenido Relacionado

Similares a 5分で分かる名前空間とオートロード (20)

Anuncio

Más reciente (20)

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宣言は必ずコードの先頭に記述すること。 (コメント、改行、スペースは宣言の前に書いてもよい) 名前空間は「」(バックスラッシュ)区切りで階層を構成できる。 <?php namespace HolyExample; //名前空間 ”HolyExample” を宣言 ※1ファイル内では1つの名前空間で完結させることを推奨
  4. 4. 名前空間を宣言する namespace宣言は必ずコードの先頭に記述すること。 (コメント、改行、スペースは宣言の前に書いてもよい) 名前空間は「」(バックスラッシュ)区切りで階層を構成できる。 <?php namespace HolyExample; //名前空間 ”HolyExample” を宣言 ちなみに、誤っていわゆるBOM付UTF-8でファイルを保存したところ、 こんなエラーで怒られてしまいました。 Fatal error: Namespace declaration statement has to be 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();//Exception PHP_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-14 http://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, implements class 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 exception 'HolyExampleUnknownException' 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 ありがとうございました。

×