ホームページ  >  記事  >  バックエンド開発  >  PHP ソース コード ext/mysql 拡張_PHP チュートリアル

PHP ソース コード ext/mysql 拡張_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-21 15:45:38944ブラウズ

外部モジュール拡張機能を作成しましたが、PHP ソース コード内の mysql 拡張機能を調べ始めています。これは PHP に統合できるため、組み込み拡張機能と見なす必要があります。
この拡張機能は、mysql データベースによって提供されるいくつかのインターフェイスを使用する必要があるため、mysql をインストールし、mysql.h の場所を特定できるようにする必要があります。
この拡張機能の場所は通常、PHP-source-code/ext/mysql の下にあります。
Linux では、注意すべき主なファイルは config.m4、php_mysql.c、php_mysql_structs.h です。
ps: このディレクトリにはタグ ファイルがあるため、ctags のさまざまな機能を使用して関数やマクロ定義などを直接検索できます。
追記: Linux で mysql を起動します sudo mysql-dir/bin/mysqld_safe &
その後 2 つのプロセスが実行されます:

コードをコピーします コードは次のとおりです:

root 5297 0.0 0.0 5920 1416 pts /5 S 11:08 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe
mysql 5320 1.4 1.1 202728 23796 ポイント/5 Sl 11:08 1:47 /usr/local/mysql/libexec/mysqld --basedir =/usr/local/mysql --datadir=/usr/local/mysql/var --user=mysql --pid-file=/usr/local/mysql/var/tj1clnxweb0004.pid --skip-external -locking - -port=3306 --socket=/tmp/mysql.sock

---------------------------- --- -------------
以下は読み取りプロセス中の詳細を記録します:
1. php_mysql_do_query_general 関数
この拡張機能によって提供される関数 mysql_query および mysql_unbuffered_query は、最終的に php_mysql_do_query_general を使用してコアを実行します。機能。
最初にトレース モードを確認します:
if (MySG(trace_mode)) { .... }
php.ini に設定があります:
mysql.trace_mode = Off
設定がオンになっている場合、if は次のようになります。実行文を選択し、実行文を選択した場合、SQL文のパフォーマンスを解析するために前にExplainを追加します。
次に、mysql_use_result と mysql_store_result の違いを見てください:
ご覧のとおり、mysql_query は mysql_store_result 関数を使用しますが、mysql_unbuffered_query は mysql_use_result を使用します。
記事 (http://school.cnd8.com/mysql/jiaocheng/25143_8.htm) を参照して、次のように要約します:
mysql_store_result はクエリを実行してすべての結果セットを取得し、それらをクライアントに保存し、使用できるように準備します。そのため、クライアントのメモリ要件とパフォーマンス要件が大きくなります。
mysql_use_result はクエリのみを実行しますが、結果の取得が遅れます。これは、サービス フロントエンドで結果セットを維持することと同じです。
mysql_store_result を呼び出し、mysql_fetch_row を使用して結果を取得した後、結果はクライアントから直接取得されます。戻り値が NULL の場合、結果はありません。
mysql_use_result を呼び出し、mysql_fetch_row を使用して結果を取得した後、戻り値が NULL の場合、結果は役に立たない可能性があります。または、ネットワーク接続エラーまたはその他の理由が考えられます。
結果セットのメンテナンス場所が異なるため、mysql_store_result の結果は、任意のシーク、合計数の取得、非順次アクセスなどのより多くの処理機能を提供できます。 mysql_use_result の結果セットは使用できません。
さらに、mysql_use_result の結果セットはサーバー側で維持されるため、クライアントは結果セット内の各行に対して mysql_fetch_row を呼び出す必要があるという要件が提示されます。そうしないと、結果セット内の残りのレコードが次のクエリになります。結果セットの一部が削除され、「非同期」エラーが発生します。
それでは、なぜ mysql_use_result を使用する必要があるのでしょうか?この状況を見てください:
mysql と mysqldump はデフォルトで mysql_store_result を使用しますが、--quick オプションが指定されている場合は、mysql_use_result が使用されます。
つまり、効率の面では mysql_use_result の方が有利ということですか?
mysql ヘルプマニュアルを参照してください:
-q、-quick 結果をキャッシュせず、行ごとに出力します。これにより、
mysqldump 出力が一時停止されると、サーバーの速度が低下する可能性があります。ヘルプマニュアル:
-q、--quick クエリをバッファリングせず、stdout に直接ダンプします
そこで、quick が mysql_use_result に対応する理由を完全に理解する前に、mysql_use_result を使用しない方がよい場合をまず考えてみましょう。 mysql_use_result の結果セットはサーバー側で保持されるため、クライアントプログラムがハングする可能性がある場合は使用しないでください。結果セット内の行間に操作が多すぎる場合は、これを使用しないでください。言い換えれば、クエリが完了し、結果がすぐに使い尽くされて解放されない場合は、mysql_use_result を使用しないでください。
効果を試すために、次のテストコードを書きました:


コードをコピーします コードは次のとおりです:
$sql = sprintf("select * from pet;"); = mysql_unbuffered_query($sql, $conn);
$rows = mysql_fetch_row($result);
$sql = sprintf("select * from shop"); $conn);
$rows = mysql_fetch_row($result);
実行の結果、2 回目のフェッチでは最初の結果は表示されませんが、PHP は次の通知を報告します。
PHP 通知: mysql_unbuffered_query(): / 内の以前のバッファリングされていないクエリから最初にすべての行をフェッチせずに関数が呼び出されました。 home/yicheng /test-all/mysqltest/test.php の 28 行目
テスト コードを変更します:
コードをコピーします コードは次のとおりです:

$i =
while($i --){
$sql = sprintf("select * from pet;");
$result = mysql_query($sql, $conn);
#$result = mysql_unbuffered_query($sql, $conn); rows = mysql_fetch_row($result)) {

}
if ($result){
mysql_free_result($result);
}
}

unbuffered を使用した結果:
:!time ./test.php
real 1m10.220s
user 0m1 7.853s
sys 0m9.541s
mysql_query を使用した結果:
:!time ./test.php
real 1m11.191s
user 0m19.297s
sys 0m10.133 s
その時期のようです違いは大きくありません
2. いくつかのリソース関連のマクロ定義

コードをコピーします コードは次のとおりです:
#define ZEND_VERIFY_RESOURCE(rsrc)
if (!rsrc) {
RETURN_FALSE;
# ZEND_FETCH_RESOURCE(rsrc、rsrc_type、passed_id、default_id、resource_type_name、resource_type) を定義します
rsrc = (rsrc_type) zend_fetch_resource(passed_id TSRMLS_CC、default_id、resource_type_name、NULL、1、resource_type)
ZEND_VERIFY_RESOURCE(rsrc); ZEND_FETCH_RESOURCE2(rsrc 、rsrc_type、passed_id、default_id、resource_type_name、resource_type1、resource_type2)
rsrc = (rsrc_type) zend_fetch_resource(passed_id TSRMLS_CC、default_id、resource_type_name、NULL、2、resource_type1、resource_type2)
#define ZEND_REGISTER_RESOURCE(rsrc_result, rsrc_pointer, rsrc_type)
zend_register _resource(rsrc_result, rsrc_pointer, rsrc_type);
# ZEND_GET_RESOURCE_TYPE_ID(le_id, le_type_name)
if (le_id == 0) {
le_id = zend_fetch_list_dtor_id(le_type_name) ;
}


私たちが返すものmysql_connect 関数は実際にはリンク ID (タイプ (mysql link ) の resource(4)) であり、ZEND_FETCH_RESOURCE および ZEND_FETCH_RESOURCE2 マクロを通じて、対応する mysql リソースにマップできます。どちらのマクロも zend_fetch_resource メソッドを呼び出します。そのため、以下でこのメソッドを見てみましょう。
ZEND_API void *zend_fetch_resource(zval **passed_id TSRMLS_DC, int default_id, char *resource_type_name, int *found_resource_type, int num_resource_types, ...)
たとえば、mysql_list_dbs 関数で ZEND_FETCH_RESOURCE2 マクロを呼び出します:
ZEND_FETCH_RESOURCE2 ( mysql、php_mysql_conn * 、mysql_link、id、"MySQL-Link"、le_link、le_plink);
Mysql は返された有効なリソースを保存します。php_mysql_conn * 返されたリソースのタイプを定義します。mysql_link、id はそれぞれ、passed_id とdefault_id に対応します (多くの関数呼び出しが渡されないため)特定の conn はデフォルト値を使用します)、「MySQL-Link」は resource_type_name、le_link、le_plink は zend_fetch_resource の一部であり、両方とも静的な int 型の値です。
zend_fetch_resource から、タイプ (mysql リンク) の resource(4) の value.lval に長いタイプ ID が含まれていることがわかります。 default_id が -1 の場合は、passed_id によって渡された ID が使用され、それ以外の場合は、default_id が ID として使用され、対応するリソースの検索に zend_list_find が使用されます。
いくつかの関数を調べた結果、この拡張機能は mysql によって提供される C インターフェイスをカプセル化したものであることがわかりました。しかし、パッケージは非常に標準化されており、安定しています。
さらに詳しく知りたい場合は、やはり MYSQL のソース コードを参照する必要があります。いくつかの重要なデータ構造を以下に掲載します。
------------------------------------------------------
役立つかもしれないいくつかのことPHP 関数のトラブルシューティング:



コードをコピー
コードは次のとおりです: error_reporting(E_ALL); #var_dump(mysql_get_proto_info($conn));
# var_dump(mysql_get_server_info($conn));
#var_dump(mysql_stat($conn));
#var_dump(mysql_error($conn));コ));


------------------------------------------- ----
MYSQL ソース コード (いくつかの便利な構造体)



コードをコピー

コードは次のとおりです:

typedef struct st_mysql
{
NET ネット; /* 通信パラメータ */
gptr Connector_fd; /* SSL 用 ConnectorFd */
char *host,*user,*passwd,*unix_socket,*server_version,*host_info,*info;
char *db;
struct charset_info_st *charset;
MYSQL_FIELD *フィールド;
MEM_ROOT フィールド_割り当て;
my_ulonglong 影響を受けた_行数;
my_ulonglong insert_id; /* NEXTNR を使用してテーブルに挿入する場合の ID */
my_ulonglong extra_info; /* 使用されません */
unsigned long thread_id; /* サーバーでの接続用の ID */
unsigned long packet_length;
未署名の int ポート。
符号なしの長い client_flag,server_capabilities;
unsigned int プロトコルバージョン;
unsigned int field_count;
unsigned intserver_status;
unsigned int サーバー言語;
unsigned int warning_count;
st_mysql_options オプションを構造化します。
enum mysql_status ステータス;
my_bool free_me; /* mysql_close が空いている場合 */
my_bool 再接続; /* 自動再接続の場合は 1 に設定 */
/* セッション全体のランダムな文字列 */
char scramble[SCRAMBLE_LENGTH+1];
/*
これが mysql_rpl_probe() または mysql_set_master()/ mysql_add_slave() によって追加されたマスターまたはスレーブではなく、元の接続であるかどうかを設定します
*/
my_bool rpl_pivot;
/*
マスターへのポインタ、および次のスレーブ接続は、単独の接続の場合は
自身を指します。
*/
struct st_mysql* マスター、*next_slave;
struct st_mysql* last_used_slave; /* ラウンドロビンのスレーブ選択に必要 */
/* レプリケーションで正しく動作するために結果の送信/読み取り/保存/使用に必要 */
struct st_mysql* last_used_con;
リスト *stmts; /* すべてのステートメントのリスト */
const struct st_mysql_methods *methods;
void *thd;
/*
MYSQL_RES または MYSQL_STMT のブール型フラグを指します。 close がこのオブジェクトの結果セットをキャンセルする必要がある場合は、mysql_stmt_close からこのフラグ
を設定します。
*/
my_bool *unbuffered_fetch_owner;
#定義されている場合(EMBEDDED_LIBRARY) ||定義済み(EMBEDDED_LIBRARY_COMPATIBLE) || MYSQL_VERSION_ID >= 50100
/* 組み込みサーバーに必要 - 「情報」を保存するためのネット バッファーがありません */
char *info_buffer;
#endif
} MYSQL;
typedef struct st_mysql_methods
{
my_bool (*read_query_result)(MYSQL *mysql);
my_bool (*advanced_command)(MYSQL *mysql,
enum enum_server_command コマンド,
const char *header,
unsigned long header_length,
const char *arg,
unsigned long arg_length,
my_bool stop_check,
MYSQL_STMT * stmt);
MYSQL_DATA *(*read_rows)(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
unsigned int フィールド);
MYSQL_RES * (*use_result)(MYSQL *mysql);
void (*fetch_lengths)(unsigned long *to,
MYSQL_ROW カラム, unsigned int field_count);
void (*flush_use_result)(MYSQL *mysql);
#if !define(MYSQL_SERVER) ||定義済み(EMBEDDED_LIBRARY)
MYSQL_FIELD * (*list_fields)(MYSQL *mysql);
my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt);
int (*stmt_execute)(MYSQL_STMT *stmt);
int (*read_binary_rows)(MYSQL_STMT *stmt);
int (*unbuffered_fetch)(MYSQL *mysql, char **row);
void (*free_embedded_thd)(MYSQL *mysql);
const char *(*read_statistics)(MYSQL *mysql);
my_bool (*next_result)(MYSQL *mysql);
int (*read_change_user_result)(MYSQL *mysql, char *buff, const char *passwd);
int (*read_rows_from_cursor)(MYSQL_STMT *stmt);
#endif
} MYSQL_METHODS;

http://www.bkjia.com/PHPjc/320292.htmlwww.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/320292.html技術記事私は、最初に PHP ソースコードを参照する際に存在する外部モジュールの拡張を書きましたが、これは PHP の内部に収集できるため、この拡張は内部拡張として使用する必要があります。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。