ホームページ バックエンド開発 PHPチュートリアル PHP 拡張機能と埋め込みリソース データ タイプ 2

PHP 拡張機能と埋め込みリソース データ タイプ 2

Jun 23, 2016 pm 01:58 PM
php 埋め込む データの種類 リソース

リソース変数に格納される複雑なデータ型は、通常、初期化中にメモリ割り当て、CPU 時間、またはネットワーク通信を必要とします。ただし、リクエスト間のデータベース接続などのリソースの保持には耐久性が必要です。リソースの耐久性は考慮する必要がある要素です。


まずメモリ割り当ての問題を見てみましょう:

PHP を使用するときは、malloc の再利用バージョンである emalloc を使用することを好みます。ただし、リクエスト間に永続的なリソースが存在する必要があります。ファイル ハンドル リソースの場合、ファイル名を保存する要件を追加する場合は、次のコードをヘッダー ファイルに追加する必要があります:

typedef struct _php_sample_descriptor_data {    char *filename;    FILE *fp;} php_sample_descriptor_data;
ログイン後にコピー
この構造体は、ファイル名とファイル ハンドル リソースを保存するために使用できます。リクエスト間の異なる共有で使用されます。


これに応じて、ソース ファイルに対応する変更を加える必要があります。

static void php_sample_descriptor_dtor( //这个是进行资源回收的回调函数,定义在资源的初始化处。                    zend_rsrc_list_entry *rsrc TSRMLS_DC){    php_sample_descriptor_data *fdata =                (php_sample_descriptor_data*)rsrc->ptr;    fclose(fdata->fp);    efree(fdata->filename);    efree(fdata);}
ログイン後にコピー
この静的関数はリソースをリサイクルするために使用され、リソースの初期化時にコールバックを指定する必要があります。


変更されたファイルを開く関数を実行するには、リソースにスペースを割り当てる操作を追加する必要があります:

PHP_FUNCTION(sample_fopen) //修改后的fopen{    php_sample_descriptor_data *fdata;    FILE *fp;    char *filename, *mode;    int filename_len, mode_len;    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",                        &filename, &filename_len,                        &mode, &mode_len) == FAILURE) {// 获取文件名和文件长度         RETURN_NULL();    }    if (!filename_len || !mode_len) {        php_error_docref(NULL TSRMLS_CC, E_WARNING,                "Invalid filename or mode length");        RETURN_FALSE;    }    fp = fopen(filename, mode);    if (!fp) {        php_error_docref(NULL TSRMLS_CC, E_WARNING,                "Unable to open %s using mode %s",                filename, mode);        RETURN_FALSE;    }    <strong>fdata = emalloc(sizeof(php_sample_descriptor_data)); //给包含了文件资源和文件名的结构分配空间    fdata->fp = fp;    fdata->filename = estrndup(filename, filename_len);</strong>    ZEND_REGISTER_RESOURCE(return_value, fdata,                                le_sample_descriptor); // 注册资源}
ログイン後にコピー

ファイル書き込み関数 fwrite も変更する必要があります:

PHP_FUNCTION(sample_fwrite){    php_sample_descriptor_data *fdata;    zval *file_resource;    char *data;    int data_len;    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs",            &file_resource, &data, &data_len) == FAILURE ) {        RETURN_NULL();    }    <strong>ZEND_FETCH_RESOURCE(fdata, php_sample_descriptor_data*,        &file_resource, -1,        PHP_SAMPLE_DESCRIPTOR_RES_NAME, le_sample_descriptor);</strong>    RETURN_LONG(fwrite(data, 1, data_len, fdata->fp));} 
ログイン後にコピー

実際のリソースを操作しないため、sample_fclose 関数は何も変更しません。次の関数は、リソースから元のファイル名を取得できます:

PHP_FUNCTION(sample_fname){    php_sample_descriptor_data *fdata;    zval *file_resource;    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r",            &file_resource) == FAILURE ) {        RETURN_NULL();    }    <strong>ZEND_FETCH_RESOURCE(fdata, php_sample_descriptor_data*,        &file_resource, -1,        PHP_SAMPLE_DESCRIPTOR_RES_NAME, le_sample_descriptor);</strong>    RETURN_STRING(fdata->filename, 1);} 
ログイン後にコピー


メモリ割り当てが完了した後、永続性を維持する必要があるため、破棄を遅らせる必要があります:


非永続性の場合リソースの場合、リソース ID を格納する変数が設定解除されるかスコープ外になると、それらは EG (regulator_list) から削除されます。 EGで使用されるインデックス(persistent_list)はkey-value型であり、リクエスト終了時に要素は自動的に削除されません。 zend_hash_del() が呼び出された場合、またはスレッド/プロセスが完全にシャットダウンされた場合にのみ削除されます。

EG(persistent_list) にも dtor メソッドがありますが、これは zend_register_list_descructors_ex() の 2 番目のパラメータです。一般に、非永続リソースと永続リソースは 2 種類として登録されますが、1 つに結合される場合もあります。次に、sample.c に永続リソース タイプを追加します。

    static int le_sample_descriptor_persist;    static void php_sample_descriptor_dtor_persistent(                    zend_rsrc_list_entry *rsrc TSRMLS_DC){<strong>//这是一个持久化的资源析构函数</strong>    php_sample_descriptor_data *fdata =                (php_sample_descriptor_data*)rsrc->ptr;    <strong>fclose(fdata->fp);    pefree(fdata->filename, 1);    pefree(fdata, 1);</strong>}PHP_MINIT_FUNCTION(sample){    le_sample_descriptor =     zend_register_list_destructors_ex(            php_sample_descriptor_dtor, NULL,            PHP_SAMPLE_DESCRIPTOR_RES_NAME, module_number);    <strong>le_sample_descriptor_persist =                        zend_register_list_destructors_ex(            NULL, php_sample_descriptor_dtor_persistent,            PHP_SAMPLE_DESCRIPTOR_RES_NAME, module_number);//注册一个持久化的资源</strong>    return SUCCESS;} 
ログイン後にコピー

次の fopen 関数は、永続リソース タイプと非永続リソース タイプの両方と互換性があります:

PHP_FUNCTION(sample_fopen){    php_sample_descriptor_data *fdata;    FILE *fp;    char *filename, *mode;    int filename_len, mode_len;    zend_bool persist = 0;    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"ss|b",                &filename, &filename_len, &mode, &mode_len,                &persist) == FAILURE) {        RETURN_NULL();    }    if (!filename_len || !mode_len) {        php_error_docref(NULL TSRMLS_CC, E_WARNING,                "Invalid filename or mode length");        RETURN_FALSE;    }    fp = fopen(filename, mode);    if (!fp) {        php_error_docref(NULL TSRMLS_CC, E_WARNING,                "Unable to open %s using mode %s",                filename, mode);        RETURN_FALSE;    }    if (!persist) {//非持久化的资源        fdata = emalloc(sizeof(php_sample_descriptor_data));        fdata->filename = estrndup(filename, filename_len);//这个做了申请内存和赋值两步操作         fdata->fp = fp;        ZEND_REGISTER_RESOURCE(return_value, fdata,                                le_sample_descriptor);    } else {//持久化的资源        list_entry le;        char *hash_key;                  int hash_key_len;        fdata =pemalloc(sizeof(php_sample_descriptor_data),1);        fdata->filename = pemalloc(filename_len + 1, 1);        memcpy(fdata->filename, filename, filename_len + 1);        fdata->fp = fp;        ZEND_REGISTER_RESOURCE(return_value, fdata,                        le_sample_descriptor_persist);        /* Store a copy in the persistent_list 在persistent_list存储一份副本 */        le.type = le_sample_descriptor_persist;        le.ptr = fdata;        hash_key_len = spprintf(&hash_key, 0,                "sample_descriptor:%s:%s", filename, mode);        zend_hash_update(&EG(persistent_list),            hash_key, hash_key_len + 1,            (void*)&le, sizeof(list_entry), NULL);        efree(hash_key);    }} 
ログイン後にコピー

非永続リソースの場合、数値インデックスが指定され、リクエストに依存する in リストに格納されます。

永続リソースの場合、キー値タイプを指定すると、後続のリクエストでハッシュキーを取得できます。次に、リソースを永続リストに追加します。 永続リソースがスコープ外になると、EG (regulator_list) のデストラクターは le_sample_descriptro_persist の registerlist デストラクターをチェックします。 NULL であることが判明した場合、操作は実行されません。これにより、永続的なリソースが解放されなくなります。 リソースが EG (persistent_list) から削除されると、スレッド プロセスが終了するか、意図的に削除されます。この時点で、永続的なデストラクターを探します。



リソースが永続的として適用される理由は、他のリクエストで 再利用するためです:


永続的なリソースを再利用したい場合は、sample_fopen が呼び出されるときに、それらの hash_key を使用する必要があります。関数は、要求されたファイル名とパターンを使用して hash_key を再作成し、persistent_list での検索を試みます。

PHP_FUNCTION(sample_fopen){    php_sample_descriptor_data *fdata;    FILE *fp;    char *filename, *mode, *hash_key;    int filename_len, mode_len, hash_key_len;    zend_bool persist = 0; //判断是否持久    list_entry *existing_file;    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"ss|b",                &filename, &filename_len, &mode, &mode_len,                &persist) == FAILURE) {        RETURN_NULL();    }    if (!filename_len || !mode_len) {        php_error_docref(NULL TSRMLS_CC, E_WARNING,                "Invalid filename or mode length");        RETURN_FALSE;    }    <strong>/* 通过获得一个hash_key尝试寻找一个已经打开的文件 */    hash_key_len = spprintf(&hash_key, 0,            "sample_descriptor:%s:%s", filename, mode);                                                                                                                  if (zend_hash_find(&EG(persistent_list), hash_key,            hash_key_len + 1, (void **)&existing_file) == SUCCESS) {        /* 成功的找到了这个已经打开的文件句柄资源 */        ZEND_REGISTER_RESOURCE(return_value,            existing_file->ptr, le_sample_descriptor_persist);        efree(hash_key);        return;    }</strong>    fp = fopen(filename, mode);    if (!fp) {        php_error_docref(NULL TSRMLS_CC, E_WARNING,                "Unable to open %s using mode %s",                filename, mode);        RETURN_FALSE;    }    if (!persist) {        fdata = emalloc(sizeof(php_sample_descriptor_data));        fdata->filename = estrndup(filename, filename_len);        fdata->fp = fp;        ZEND_REGISTER_RESOURCE(return_value, fdata,                                le_sample_descriptor);    } else {        list_entry le;        fdata =pemalloc(sizeof(php_sample_descriptor_data),1);        fdata->filename = pemalloc(filename_len + 1, 1);        memcpy(data->filename, filename, filename_len + 1);        fdata->fp = fp;        ZEND_REGISTER_RESOURCE(return_value, fdata,                        le_sample_descriptor_persist);        /* Store a copy in the persistent_list */        le.type = le_sample_descriptor_persist;        le.ptr = fdata;        /* hash_key has already been created by now */        zend_hash_update(&EG(persistent_list),            hash_key, hash_key_len + 1,            (void*)&le, sizeof(list_entry), NULL);    }    efree(hash_key);}
ログイン後にコピー

すべての拡張機能は同じハッシュ テーブルを使用してリソースを保存するため、名前付けが重要であることに注意してください。一般に、拡張機能とリソース タイプの名前はプレフィックスとして使用されます。



リソースの可用性を確認します:


    尽管像文件这种资源可以长期打开,但是类似远程网络资源这种如果在请求之间长期不用的话就有问题。 所以在使用一个persistent资源之前,要先确定可用性。

if (zend_hash_find(&EG(persistent_list), hash_key,        hash_key_len + 1, (void**)&socket) == SUCCESS) {    if (php_sample_socket_is_alive(socket->ptr)) {        ZEND_REGISTER_RESOURCE(return_value,                    socket->ptr, le_sample_socket);        return;    }    zend_hash_del(&EG(persistent_list),                            hash_key, hash_key_len + 1); //这里会去调用之前注册好的析构函数}
ログイン後にコピー








   


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Ubuntu および Debian 用の PHP 8.4 インストールおよびアップグレード ガイド Ubuntu および Debian 用の PHP 8.4 インストールおよびアップグレード ガイド Dec 24, 2024 pm 04:42 PM

PHP 8.4 では、いくつかの新機能、セキュリティの改善、パフォーマンスの改善が行われ、かなりの量の機能の非推奨と削除が行われています。 このガイドでは、Ubuntu、Debian、またはその派生版に PHP 8.4 をインストールする方法、または PHP 8.4 にアップグレードする方法について説明します。

CakePHP データベースの操作 CakePHP データベースの操作 Sep 10, 2024 pm 05:25 PM

CakePHP でデータベースを操作するのは非常に簡単です。この章では、CRUD (作成、読み取り、更新、削除) 操作について理解します。

CakePHP の日付と時刻 CakePHP の日付と時刻 Sep 10, 2024 pm 05:27 PM

Cakephp4 で日付と時刻を操作するには、利用可能な FrozenTime クラスを利用します。

CakePHP ファイルのアップロード CakePHP ファイルのアップロード Sep 10, 2024 pm 05:27 PM

ファイルのアップロードを行うには、フォーム ヘルパーを使用します。ここではファイルアップロードの例を示します。

CakePHP について話し合う CakePHP について話し合う Sep 10, 2024 pm 05:28 PM

CakePHP は、PHP 用のオープンソース フレームワークです。これは、アプリケーションの開発、展開、保守をより簡単にすることを目的としています。 CakePHP は、強力かつ理解しやすい MVC のようなアーキテクチャに基づいています。モデル、ビュー、コントローラー

CakePHP バリデータの作成 CakePHP バリデータの作成 Sep 10, 2024 pm 05:26 PM

Validator は、コントローラーに次の 2 行を追加することで作成できます。

CakePHP のロギング CakePHP のロギング Sep 10, 2024 pm 05:26 PM

CakePHP へのログインは非常に簡単な作業です。使用する関数は 1 つだけです。 cronjob などのバックグラウンド プロセスのエラー、例外、ユーザー アクティビティ、ユーザーが実行したアクションをログに記録できます。 CakePHP でのデータのログ記録は簡単です。 log()関数が提供されています

PHP 開発用に Visual Studio Code (VS Code) をセットアップする方法 PHP 開発用に Visual Studio Code (VS Code) をセットアップする方法 Dec 20, 2024 am 11:31 AM

Visual Studio Code (VS Code とも呼ばれる) は、すべての主要なオペレーティング システムで利用できる無料のソース コード エディター (統合開発環境 (IDE)) です。 多くのプログラミング言語の拡張機能の大規模なコレクションを備えた VS Code は、

See all articles