このようなミニフレームワークは通常、mod_rewriteの次のルールに基づいています。
Copy Source | Copy HTML < IfModule mod_rewrite . c > RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </ IfModule >
Copy Source | Copy HTML < IfModule mod_rewrite . c > RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </ IfModule >
Copy Source | Copy HTML < IfModule mod_rewrite . c > RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </ IfModule >
Copy Source | Copy HTML < IfModule mod_rewrite . c > RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </ IfModule >
Copy Source | Copy HTML < IfModule mod_rewrite . c > RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </ IfModule >
Copy Source | Copy HTML < IfModule mod_rewrite . c > RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </ IfModule >
Copy Source | Copy HTML < IfModule mod_rewrite . c > RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </ IfModule >
Copy Source | Copy HTML < IfModule mod_rewrite . c > RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L] </ IfModule >
それらは、フレームワークが接続されているindex.phpにリクエストをリダイレクトし、このリクエストはコールバック関数で処理されます。 そのため、まず、アドレスを処理する簡単な関数を作成します。
Copy Source | Copy HTML
- 関数リクエスト( $パス 、 $コールバック )
- {
- if ( $ path == $ _SERVER [ 'REQUEST_URI' ]) return call_user_func( $ callback );
- }
呼び出されると、関数はユーザーがアクセスしたアドレスをチェックし、関数に渡されたアドレスと一致する場合、コールバックを呼び出します。 これはすでに基本的な機能と見なすことができます。 ただし、アドレスから変数を抽出するという必要なものはありません。 さらに、 example.com / somethingとexample.com/somethingのアドレスは、関数によって異なると見なされます。 これを解決するには、アドレスを解析してarray_filterを使用します。
Copy Source | Copy HTML
- 関数 array_filter_callback_no_empty_str( $ value )
- {
- return $ value != '' ;
- }
- 関数リクエスト( $パス 、 $コールバック )
- {
- //コールバックに渡す変数をリクエストします
- $ args = array ();
- //ユーザーがアクセスしたアドレス(URI)を部分に分割します
- $ uri = explode( '/' 、 $ _SERVER [ 'REQUEST_URI' ]);
- //クエリパスで同じことを行います
- $ path = explode( '/' 、 $ path );
- //両方の配列の空の部分を削除します
- $ uri = array_values(array_filter( $ uri 、array_filter_callback_no_empty_str));
- $ path = array_values(array_filter( $ path 、array_filter_callback_no_empty_str));
- // URIのパーツ数とパスが異なる場合、終了
- if (count( $ uri )!= count( $ path ))
- falseを返します 。
- //リクエストパスのすべての部分を調べます
- for ( $ i = 0 ; $ i <count( $ path ); $ i ++)
- {
- //パスの指定された部分が変数であるかどうかを確認します
- //変数パスは中括弧で囲まれ、正規表現をチェックします
- if (preg_match( '| ^ \ {(。*)\} $ |' 、 $ path [ $ i ]、 $ match ))
- {
- //ある場合、この変数を配列に追加します
- $ args [ $ match [ 1 ]] = $ uri [ $ i ];
- }
- 他に
- {
- //リクエストの一部が変数ではない場合、URIとリクエストを比較します
- //一致しない場合、終了します
- if ( $ uri [ $ i ]!= $ path [ $ i ])
- falseを返します 。
- }
- }
- //すべてのチェックの後、コールバックを呼び出し、リクエスト変数を含む配列を渡します
- return call_user_func_array( $ callback 、 $ args );
- }
これで、次のようなコードを作成できます。
Copy Source | Copy HTML
- 関数 Hello( $ who )
- {
- print "Hello、$ who" ;
- }
- リクエスト( '/ hello / {who}' 、こんにちは);
それでは、Silexを見て、何が欠けているのか見てみましょう。 まず第一に、これらはアサーション(正規表現に対するパス変数のチェック)、呼び出しメソッド(GET、POST、PUTなど)およびオブジェクト指向モデルのチェックです。 最初の2つは非常に簡単に追加できます。チェックをいくつか追加するだけです。
Copy Source | Copy HTML
- 関数リクエスト( $ method 、 $ path 、 $ callback 、 $ asserts = array ())
- {
- //サーバーにアクセスする方法を確認します。
- //特定のメソッドがリクエストで指定され、使用されたメソッドと一致しない場合、終了します
- if ( $ method != '' && strtolower( $ _SERVER [ 'REQUEST_METHOD' ])!= $ method )
- falseを返します 。
- <...>
- //パスの指定された部分が変数であるかどうかを確認します
- if (preg_match( '| ^ \ {(。*)\} $ |' 、 $ path [$ i]、 $ match ))
- {
- //存在する場合は、テストする正規表現があるかどうかを確認し、
- //そして、もしあれば、URIの対応する部分への準拠をチェックします
- if (! isset ( $ asserts [ $ match [ 1 ]]))|| preg_match( $ asserts [ $ match [ 1 ]]、 $ uri [$ i]))
- {
- //すべてが正しい場合、この変数をその値とともに配列に追加します
- $ args [ $ match [ 1 ]] = $ uri [$ i];
- }
- 他に
- {
- //値が正規表現と一致しない場合、終了します
- falseを返します 。
- }
- }
- <...>
- }
ただし、2番目も非常に簡単です。 $メソッド、$パス、$コールバックをコンストラクタに渡し、アサートのために別個のラッパー関数を作成し、すべての作業をrun()関数に入れます。上記の変数の代わりに$ this->を使用することを忘れないでください。
Copy Source | Copy HTML
- クラスリクエスト
- {
- パブリック $メソッド ; //リクエストメソッド(GET、POST、PUTなど)
- パブリック $パス ; //リクエストパス
- パブリック $コールバック 。 //コールバック
- public $ asserts = array (); //パス変数をチェックするための正規表現
- //クラスコンストラクター
- パブリック関数 __construct( $ method 、 $ path 、 $ callback )
- {
- $ this-> method = strtolower( $ method );
- $ this- > path = $ path ;
- $ this-> callback = $ callback ;
- }
- // re regexを追加して、nameという名前のパス変数をテストします
- パブリック関数 assert( $ name 、 $ re )
- {
- $ this-> asserts [ $ name ] = $ re ;
- //クラスの現在のインスタンスを返します
- //これにより、同様のコードを記述できます。$ reg-> assert( 'id'、 '| ^ \ d + $ |')-> run();
- $ thisを 返します。
- }
- //リクエスト処理関数
- パブリック関数 run()
- {
- <...>
- }
- }
2点を除いて、すべてが美しいようです。 最初のポイントは純粋に美的です-1つのリクエストを処理するには、2行のコードを書く必要があります。
Copy Source | Copy HTML
- $ req = new Request( '/ user / {id}' 、UserProfile);
- $ req- > assert( '| ^ \ d + $ |' )-> run();
しかし幸いなことに、PHPではクラスと関数に同じ名前を使用できるため、クラスのインスタンスを作成して返すラッパー関数を作成します。
Copy Source | Copy HTML
- 関数リクエスト( $メソッド 、 $パス 、 $コールバック )
- {
- 新しいリクエストを返す ( $メソッド 、 $パス 、 $コールバック );
- }
これで、すべてをコンパクトかつ便利に書き直すことができます。
Copy Source | Copy HTML
- リクエスト( '/ user / {id}' 、UserProfile)-> assert( '| ^ \ d + $ |' )-> run();
2番目の不快な瞬間は、リクエストを保存して処理するセンターが1つもないことです。 なぜrun()関数を常に呼び出す必要があるのですか? ただし、このような単一のセンターを作成しても、新しいクエリ自体がキューに追加されると、はるかに簡単になります。 さらに、センターが2つあるべきではないため、シングルトンを実装する必要があります。 それで、私たちはすでにそれを書きます!
Copy Source | Copy HTML
- クラス申請
- {
- public $ requests = array ();
- /// ---
- //シングルトンを実装します
- 保護された静的 $インスタンス 。
- プライベート関数 __construct()
- {
- }
- プライベート関数 __clone()
- {
- }
- パブリックスタティック関数 getInstance()
- {
- if (!is_object(self :: $ instance ))
- {
- self :: $ instance = new self;
- }
- return self :: $インスタンス ;
- }
- public static function init()
- {
- self :: getInstance();
- }
- /// ---
- //すべてのリクエストを処理する内部関数
- プライベート関数 i_run()
- {
- foreach ( $ this- >要求as & $ request )
- {
- $ done = $ request- > run( $ params );
- if ( $ done ) trueを返す場合 ;
- }
- falseを返します 。
- }
- // i_runの外部静的ラッパー関数
- //美学のためにのみ必要:Application :: run()はApplication :: getInstance()-> run()よりもきれいに見える
- public static function run()
- {
- return Application :: getInstance()-> i_run();
- }
- }
Requestクラスも少し変更します。
Copy Source | Copy HTML
- クラスリクエスト
- {
- <...>
- //クラスコンストラクター
- パブリック関数 __construct( $ method 、 $ path 、 $ callback )
- {
- $ this-> method = strtolower( $ method );
- $ this- > path = $ path ;
- $ this-> callback = $ callback ;
- //このリクエストをアプリケーションのキューに追加します
- アプリケーション:: getInstance()->リクエスト[] = $ this ;
- }
- <...>
- パブリック関数 run()
- {
- <...>
- //すべてのチェックの後、コールバックを呼び出し、リクエスト変数を含む配列を渡します
- $ result = call_user_func_array( $ this-> callback、 $ this-> args);
- //コールバックがブール値を返した場合、それを返します
- if (is_bool( $ result ))
- return $ result ;
- //それ以外の場合、trueを返します
- 他に
- trueを返します 。
- }
- }
後者は、1つのパスを処理するために複数の要求を使用できるようにするために必要です。 コールバックがfalseを返す場合、次のリクエストが処理されます。そうでない場合、すべてが終了します。
一般に、ミニフレームワークの使用はかなりきれいでシンプルに見えます。
Copy Source | Copy HTML
- 新しいアプリケーション();
- リクエスト( '/ user / {id}' 、UserProfile)-> assert( '| ^ \ d + $ |' )-> run();
- アプリケーション::実行();
ただし、さらに簡素化できます。 PHP設定には、auto_prepend_fileとauto_append_fileの2つの優れたオプションがあり、メインスクリプトの実行前後に事前にスクリプト化されたPHPスクリプトを接続できます。 フレームワークを別のファイルに配置し、これらの関数を使用して添付できます。 最初の接続では、クラスを宣言してApplicationオブジェクトを作成し、2番目の接続ではApplication :: run()を呼び出します。 ApplicationクラスまたはRequestクラスが存在するかどうかを確認することにより、スクリプトが初めて実行されているかどうかを判断できます。
Copy Source | Copy HTML
- if (!class_exists( 'Application' ))
- {
- // Applicationクラスがまだ宣言されていない場合、スクリプトは初めて実行されます
- クラスリクエスト
- {
- <...>
- }
- 関数リクエスト( $メソッド 、 $パス 、 $コールバック )
- {
- <...>
- }
- クラス申請
- {
- <...>
- }
- //アプリケーションの初期化、
- アプリケーション:: init();
- }
- 他に
- {
- //スクリプトは初めて実行されていません
- アプリケーション::実行();
- }
したがって、2つの「余分な」行を取り除きました。
これが、多かれ少なかれ機能的なミニフレームワークを書く方法です。 Silexには届きませんが、使用することは可能です。 完全なソースコード(わずかに変更)と使用例はhttp://fw.nizarium.com/にあり、同じミニフレームワークで動作します。
これを深刻なものと考えないでください。 これは単なる例であり、元々は私自身のために書かれたものです。 エラーがあれば、修正する準備ができています。