ABC(*1)の12日目。共通テーマは私が開発している「Risouto」についてです。
ユーザコードがコールされるまで
さて、本日は前回の続きと言うことで、Risolutoのコアコードとも言うべき「risoluto/lib/vendor/Risoluto/Core.php」のコードを見ていくことにします。このコードは前回の「index.php」から直接コールされます。
というわけで、重要そうな部分をピックアップしていくわけですが、まずはこの部分から。
/** * Perform() * * 指定されたアプリケーションを呼び出す * * @access public * * @param void なし * * @return void なし */ public function Perform() { //------------------------------------------------------// // アプリケーションクラスをロードし実行する //------------------------------------------------------// // クラスインスタンスを生成し、実行する try { // 呼び出すクラスを決定する $call = $this->FindCallClass(); // インスタンスの生成 $targetInstance = new $call['load']; // イニシャライズメソッドをコール if (method_exists($targetInstance, 'Init')) { $targetInstance->Init($call['param']); } else { // メソッドが存在しなければ例外をThrow throw new Exception($this->coreError('notfound_init')); } // HTTPのメソッドに応じて適切なコントローラをコール switch ($_SERVER['REQUEST_METHOD']) { // GETの場合 case 'GET': if (method_exists($targetInstance, 'PlayGet')) { $targetInstance->PlayGet(); } elseif (method_exists($targetInstance, 'Play')) { $targetInstance->Play(); } else { // メソッドが存在しなければ例外をThrow throw new Exception($this->coreError('notfound_play')); } break; // POSTの場合 case 'POST': if (method_exists($targetInstance, 'PlayPost')) { $targetInstance->PlayPost(); } elseif (method_exists($targetInstance, 'Play')) { $targetInstance->Play(); } else { // メソッドが存在しなければ例外をThrow throw new Exception($this->coreError('notfound_play')); } break; // PUTの場合 case 'PUT': if (method_exists($targetInstance, 'PlayPut')) { $targetInstance->PlayPut(); } elseif (method_exists($targetInstance, 'Play')) { $targetInstance->Play(); } else { // メソッドが存在しなければ例外をThrow throw new Exception($this->coreError('notfound_play')); } break; // DELETEの場合 case 'DELETE': if (method_exists($targetInstance, 'PlayDelete')) { $targetInstance->PlayDelete(); } elseif (method_exists($targetInstance, 'Play')) { $targetInstance->Play(); } else { // メソッドが存在しなければ例外をThrow throw new Exception($this->coreError('notfound_play')); } break; // OPTIONの場合 case 'OPTION': if (method_exists($targetInstance, 'PlayOption')) { $targetInstance->PlayOption(); } elseif (method_exists($targetInstance, 'Play')) { $targetInstance->Play(); } else { // メソッドが存在しなければ例外をThrow throw new Exception($this->coreError('notfound_play')); } break; // HEADの場合 case 'HEAD': if (method_exists($targetInstance, 'PlayHead')) { $targetInstance->PlayHead(); } elseif (method_exists($targetInstance, 'Play')) { $targetInstance->Play(); } else { // メソッドが存在しなければ例外をThrow throw new Exception($this->coreError('notfound_play')); } break; // TRACEの場合 case 'TRACE': if (method_exists($targetInstance, 'PlayTrace')) { $targetInstance->PlayTrace(); } elseif (method_exists($targetInstance, 'Play')) { $targetInstance->Play(); } else { // メソッドが存在しなければ例外をThrow throw new Exception($this->coreError('notfound_play')); } break; // CONNECTの場合 case 'CONNECT': if (method_exists($targetInstance, 'PlayConnect')) { $targetInstance->PlayConnect(); } elseif (method_exists($targetInstance, 'Play')) { $targetInstance->Play(); } else { // メソッドが存在しなければ例外をThrow throw new Exception($this->coreError('notfound_play')); } break; // デフォルトの場合 default: if (method_exists($targetInstance, 'Play')) { $targetInstance->Play(); } else { // メソッドが存在しなければ例外をThrow throw new Exception($this->coreError('notfound_play')); } break; } } catch (Exception $e) { // エラーハンドリングメソッドをコール if (method_exists($targetInstance, 'Error')) { $targetInstance->Error($e); } else { // メソッドが存在しなければ強制終了 die($this->coreError('notfound_error')); } } finally { // クリーニングメソッドをコール if (method_exists($targetInstance, 'Clean')) { $targetInstance->Clean(); } else { // メソッドが存在しなければ強制終了 die($this->coreError('notfound_clean')); } } }
やってることはとてもシンプルで、呼び出すクラスファイル(すなわちユーザアプリのコード)を決定して、そのインスタンスを生成して、「決められた順序」でそのインスタンス中のメソッドをコールする。その「決められた順序」でメソッドのコールができない場合はエラーとする。つまりはそれだけなのです。
この「決められた順序」っていうのは、
- Init()
- Pray()
- Clean()
の順番というのが基本となり、各メソッドで例外が発生した場合は「Error()」というメソッドがコールされる……という流れになります。
で、ちょっとややこしいのだけれども、「Pray()」メソッドはHTTPのメソッドに応じて複数定義することができたりするわけで。例えば、POSTメソッドでアクセスされた場合は「PrayPost()」というメソッドが「Pray()」の代わりにコールされます。
必須メソッドを整理するとこんな感じになります。このうち「Pray()」の代わりに「Pray{HTTPのメソッド名}()」というルールのメソッドを定義しておくと、そのHTTPメソッドでアプリケーションがアクセスされた場合にそちらが呼び出されます。
Init()
初期化処理を書く。コール時にRisoluto形式で指定されたパラメタが渡されてくる。
Pray()
主処理を書く。
Error()
エラー処理を書く。このメソッドが例外をThrowしてはならない。
Clean()
後処理を書く。
で、どのクラスインスタンスを呼び出すかをどう決めているか……というと、「Core::FindCallClass()」ってメソッドが良きようにしてくれるのです。ついでにいえば、このCoreクラスでエラー(*2)が発生した場合は、例外をThrowします。例外発生時のエラーメッセージテキストは「Core::CoreError()」というメソッドで生成する……というのが大まかな流れ。
まあ、そのあたりはまた明日。
*1:アドベント・ぼっち・カレンダーの意
*2:必須メソッドが定義されていない場合