1. DBQuery オブジェクト
DBQuery オブジェクトは単にストアド プロシージャをエミュレートするだけです。実行されると、保存する必要がある結果リソースが返されます。また、結果セットに対して関数 (num_rows() や fetch_row() など) を使用する場合も同様です。 )、MySqlDB オブジェクトを渡す必要があります。では、MySqlDB オブジェクト (実行されたクエリの結果を操作するように設計されている) によって実装される関数を DBQuery オブジェクトが実装すると、どのような影響があるのでしょうか?前の例のコードを引き続き使用し、結果リソースが DBQuery オブジェクトによって管理されていると仮定します。 DBQuery クラスのソース コードをリスト 1 に示します。
リスト 1. DBQuery クラスの使用。
'mysql_db.php' が必要です。
require_once 'query.php';
$db = 新しい MySqlDb;
$db->connect('ホスト', 'ユーザー名', 'パス');
$db->query('コンテンツ管理システムを使用');
$query = 新しい DBQuery($db);
$query->prepare('SELECT fname,sname FROM users WHERE username=:1S AND pword=:2S AND expire_time<:3I');
試す {
if($query->execute("visualad", "apron", time()))->num_rows() == 1) {
echo('正しい認証情報');
} それ以外 {
echo('不正な認証情報 / セッションの期限切れ');
}
} キャッチ (QueryException $e) {
echo('クエリ実行エラー: ' . $e);
上記の変更されたコードで最も注目すべき点は、catch ステートメントとexecute ステートメントです
。
·execute ステートメントは結果リソースを返さなくなり、DBQuery オブジェクト自体を返すようになりました。
· DBQuery オブジェクトは、DB インターフェイスですでにおなじみの num_rows() 関数を実装するようになりました。
· クエリの実行が失敗した場合、QueryException タイプの例外がスローされます。文字列に変換すると、発生したエラーの詳細が返されます。
これを行うには、プロキシを使用する必要があります。実際、すでに DBQuery オブジェクトでプロキシを使用していますが、ここではそれをさらに深く使用して、MySqlDB オブジェクトに緊密にバインドします。 DBQuery オブジェクトは、DB インターフェイスを実装するオブジェクトで初期化されており、クエリを実行する DB オブジェクトの query() メソッドを呼び出すメンバー関数executeがすでに含まれています。 DBQuery オブジェクト自体は実際にはデータベースにクエリを実行せず、このタスクを DB オブジェクトに任せます。これはプロキシであり、同じまたは類似の動作を実装する別のオブジェクトにメッセージを送信することで、オブジェクトが特定の動作を実装できるプロセスです。
これを行うには、DBQuery オブジェクトを変更して、DB オブジェクトからの結果リソースを操作するすべての関数を含める必要があります。クエリを実行するときに保存された結果を使用して、DB オブジェクトの対応する関数を呼び出し、その結果を返す必要があります。次の関数が追加されます。
リスト 2: プロキシを使用した DBQuery クラスの拡張。
クラスDBQuery
{
.....
パブリック関数 fetch_array()
{
if (! is_resource($this->result)) {
throw new Exception('クエリは実行されませんでした。');
}
return $this->db->fetch_array($this->result);
パブリック
関数 fetch_row()
{
if (! is_resource($this->result)) {
throw new Exception('クエリは実行されませんでした。');
}
return $this->db->fetch_row($this->result);
パブリック
関数 fetch_assoc()
{
if (! is_resource($this->result)) {
throw new Exception('クエリは実行されませんでした。');
}
return $this->db->fetch_assoc($this->result);
関数
fetch_object()
{
if (! is_resource($this->result)) {
throw new Exception('クエリは実行されませんでした。');
}
return $this->db->fetch_object($this->result);
パブリック
関数 num_rows()
{
if (! is_resource($this->result)) {
throw new Exception('クエリは実行されませんでした。');
}
return $this->db->num_rows($this->result);
}
各
関数の実装は非常に簡単です。まずクエリが実行されたことを確認し、次にタスクを DB オブジェクトに委任し、あたかもクエリ オブジェクトそのものであるかのように結果を返します (基本データベース関数と呼ばれます)。
2. タイプ ヒンティング
プロキシが機能するためには、DBQuery オブジェクトの $db 変数が DB インターフェイスを実装するオブジェクトのインスタンスであることを確認する必要があります。型ヒントは、関数パラメーターを特定の型のオブジェクトに強制的に変換できるようにする PHP 5 の新機能です。 PHP 5 より前では、関数パラメーターが特定のオブジェクト型であることを確認する唯一の方法は、PHP で提供される型チェック関数 (つまり is_a()) を使用することでした。関数パラメータの前に型名を付けることで、オブジェクト型を簡単にキャストできるようになりました。 DBQuery オブジェクトからの型ヒントについてはすでに説明しました。これにより、DB インターフェイスを実装するオブジェクトがオブジェクト コンストラクターに渡されるようになります。
パブリック関数 __construct(DB $db)
{
$this->db = $db;
ヒント
を使用する場合、オブジェクト型だけでなく、抽象クラスやインターフェイスも指定できます。
3. 例外をスローする
上記のコードから、キャッチしたのは QueryException と呼ばれる例外であることに気づいたかもしれません (このオブジェクトは後で実装します)。例外はエラーに似ていますが、より一般的です。例外を説明する最良の方法は、emergency を使用することです。緊急事態は「致命的」ではないかもしれませんが、それでも対処する必要があります。 PHP で例外がスローされると、関数、try..catch ブロック、またはスクリプト自体のいずれであっても、現在の実行スコープはすぐに終了します。その後、例外は呼び出しスタックを横断し、各実行スコープを終了して、try..catch ブロックにキャッチされるか呼び出しスタックの先頭に到達するまで、その時点で致命的エラーが生成されます。
例外処理は、PHP 5 のもう 1 つの新機能です。OOP と組み合わせて使用すると、エラー処理とレポートを適切に制御できます。 try..catch ブロックは、例外を処理するための重要なメカニズムです。キャッチされると、スクリプトの実行は、例外がキャッチされて処理されたコードの次の行から続行されます。
クエリが失敗した場合は、例外をスローするように実行関数を変更する必要があります。 QueryException というカスタム例外オブジェクトをスローします。エラーの原因となった DBQuery オブジェクトがそれに渡されます。
リスト 3. 例外をスローします。
/**
*現在のクエリを実行
*
* 現在のクエリを実行します。ドットは指定された引数に置き換えます。
* 。
*
* @parameters: 混合 $queryParams,... クエリ パラメータ
* @return: リソース A - クエリが実行されるリソースを説明する参照。
*/
パブリック関数実行($queryParams = '')
{
//例: SELECT * FROM table WHERE name=:1S AND type=:2I AND level=:3N
$args = func_get_args();
if ($this->stored_procedure) {
/*コンパイル関数を呼び出してクエリを取得します*/
$query = call_user_func_array(array($this, 'compile'), $args);
} それ以外 {
/*ストアド プロシージャは初期化されていないため、標準クエリとして実行されます*/
$query = $queryParams;
}
$result = $this->db->query($query);
if (! $result) {
新しい QueryException($this) をスローします。
}
$this->result = $result;
/* オブジェクト自体を返す方法に注目してください。これにより、この関数の戻り結果からメンバー関数を呼び出すことができます */
$this を返します。
4.
継承を使用してカスタム例外をスローする
PHP では、任意のオブジェクトを例外としてスローできます。ただし、まず、例外は PHP の組み込み例外クラスから継承する必要があります。独自のカスタム例外を作成すると、エラーに関するその他の情報をログに記録したり、ログ ファイルにエントリを作成したり、好きなことを行うことができます。カスタム例外は次のことを行います。
· クエリによって生成された DB オブジェクトからのエラー メッセージをログに記録します。
· コール スタックを調べて、クエリ エラーが発生したコード行の正確な詳細を提供します。
· エラー メッセージとクエリ テキストを表示します (文字列に変換された場合)。
エラー メッセージとクエリ テキストを取得するには、DBQuery オブジェクトにいくつかの変更を加える必要があります。
1. 新しい保護属性であるcompiledQueryをクラスに追加する必要があります。
2.compile() 関数は、クエリのcompiledQuery プロパティをクエリ テキストで更新します。
3. コンパイルされたクエリ テキストを取得する関数を追加する必要があります。
4. 関数も追加する必要があります。この関数は、DBQuery オブジェクトに関連付けられた現在の DB オブジェクトを取得します。
リスト 4. 例外をスローします。
クラスDBQuery
{
/**
*compile() またはexecute() を呼び出した後、コンパイルされたバージョンのクエリを保存します*
* @var string $compiledQuery
*/
保護された $compiledQuery;
/**
* コンパイルされたクエリを実行せずに返します。
* @parameters: 混合 $params,...クエリ パラメータ* @return: 文字列 - コンパイルされたクエリ*/
パブリック関数コンパイル($params='')
{
if (! $this->stored_procedure) {
throw new Exception("ストアド プロシージャが初期化されていません。");
}
/*パラメータを置き換えます*/
$params = func_get_args(); //関数パラメータを取得 $query = preg_replace("/(?compile_callback($params, 1, "2")', $this->query);
return ($this->compiledQuery = $this->add_strings($query)) //文字列をクエリに戻します。
パブリック関数 getDB()
{
$this->db を返します。
}
パブリック関数 getCompiledQuery()
{
$this->compiledQuery を返します。
}
これ
で、QueryException クラスを実装できます。実際にエラーを引き起こしたスクリプト内の場所を見つけるためにコール スタックをどのように探索するかに注目してください。これは、例外をスローする DBQuery オブジェクトが DBQuery オブジェクトを継承するサブクラスである場合にまさに当てはまります。
リスト 5: QueryException クラス。
/**
*クエリ例外
*
*クエリを実行しようとしたときにエラーが発生すると、 {@link DBQuery} オブジェクトによってエラーがスローされます。
*/
クラス QueryException は例外を拡張します
{
/**
*クエリテキスト*
* @var string $QueryText;
*/
保護された $QueryText;
/**
*データベースからのエラー番号/コード*
* @var string $ErrorCode
*/
保護された $ErrorNumber;
/**
*データベースからのエラー メッセージ*
* @var string $ErrorMessage
*/
保護された $ErrorMessage;
/**
*クラスコンストラクター*
* @Parameter: DBQuery $db、例外をスローするクエリ オブジェクト */
パブリック関数 __construct(DBQuery $query)
{
/*コールスタックを取得します*/
$backtrace = $this->GetTrace();
/*行とファイルを実際にエラーが発生した場所に設定します*/
if (count($backtrace) > 0) {
$x = 1;
/*クエリ クラスが継承されている場合は、サブクラスによる呼び出しを無視する必要があります*/
while((! isset($backtrace[$x]['line'])) ||
(isset($backtrace[$x]['class']) && is_subclass_of($backtrace[$x]['class'], 'DBQuery')) ||
(strpos(strto lower(@$backtrace[$x]['function']), 'call_user_func')) !== false ) {
/*行番号がない場合、または呼び出される関数が DBQuery クラスのサブクラスである限り、ループ実行*/
++$x;
/*スタックの一番下に到達した場合は、最初の呼び出し元を使用します*/
if (($x) >= count($backtrace)) {
$x = カウント($backtrace);
壊す;
}
}
/*上記のループが少なくとも 1 回実行される場合は、それを 1 減分して、エラーの原因となった実際のコード行を見つけることができます*/
if ($x != 1) {
$x -= 1;
}
/*最後に、エラーの原因となった SQL ステートメントを反映するファイル番号と行番号を設定できます*/
$this->line = $backtrace[$x]['line'];
$this->file = $backtrace[$x]['file'];
}
$this->QueryText = $query->getCompiledQuery();
$this->ErrorNumber = $query->getDB()->errno();
$this->ErrorMessage = $query->getDB()->error();
/*スーパークラスの例外コンストラクターを呼び出します*/
親::__construct('クエリ エラー', 0);
}
/**
*クエリテキストを取得*
* @return string クエリテキスト */
パブリック関数 GetQueryText()
{
$this->QueryText を返します。
}
/**
*エラー番号を取得しました*
* @return 文字列エラー番号 */
パブリック関数 GetErrorNumber()
{
$this->ErrorNumber を返します。
}
/**
*エラーメッセージが表示されました*
* @return 文字列エラー メッセージ */
パブリック関数 GetErrorMessage()
{
$this->ErrorMessage を返します;
}
/**
* オブジェクトが文字列に変換されるときに呼び出されます。
* @戻り文字列 */
パブリック関数 __toString()
{
$output = "{$this->file} 行 {$this->line}nn のクエリ エラー";
$output .= "クエリ: {$this->QueryText}n";
$output .= "エラー: {$this->ErrorMessage} ({$this->ErrorNumber})nn"
;
}
、
このセクションの冒頭で見たコードが機能するようになりました。
5. 結論
この記事では、エージェントがクエリに関連付けられた DB インターフェイスを特定のクエリ結果に対する操作にどのようにマッピングするかを説明しました。 DBQuery オブジェクトは、fetch_assoc() などの DB オブジェクトと同じ関数を公開します。ただし、これらはすべて 1 つのクエリに対して機能します。また、カスタム例外を使用してエラーが発生したときと場所に関する詳細情報を提供する方法と、エラー処理をより適切に制御する方法についても学びました。