PHP はグローバルステータスを管理します
グローバル状態の管理
命令型言語では、何らかのグローバル領域が常に必要です。 PHP または拡張機能をプログラミングするときは、いわゆるリクエストバインドされたグローバル変数と真のグローバル変数を明確に区別します。
リクエスト グローバル変数は、リクエストの処理中に情報を保持および記憶する必要があるグローバル変数です。簡単な例としては、関数パラメータに値を指定するようにユーザーに要求し、その値を他の関数で使用できるようにしたい場合があります。この情報は、複数の PHP 関数呼び出しにわたって「値を保持」することを除いて、現在のリクエストの値のみを保持します。次に来るリクエストは何も知らないはずです。 PHP は、選択したマルチプロセッシング モデルに関係なく、リクエストのグローバル変数を管理するメカニズムを提供します。これについては、この章で後ほど詳しく説明します。
実際のグローバル変数は、リクエスト間で保持される情報です。通常、この情報は読み取り専用です。リクエスト処理の一環としてこのようなグローバル変数に書き込む必要がある場合、PHP では役に立ちません。マルチプロセッシング モデルとしてスレッドを使用する場合は、メモリ ロックを自分で実装する必要があります。マルチプロセッシングモデルとしてプロセスを使用する場合は、独自の IPC (プロセス間通信) を使用する必要があります。ただし、これは PHP 拡張プログラミングでは発生すべきではありません。
関連する学習の推奨事項: PHP プログラミングの入門から習熟まで
リクエスト グローバル変数の管理
次はリクエスト グローバル変数です。変数 単純な拡張機能の例:
/* 真正的 C 全局 */ static zend_long rnd = 0; static void pib_rnd_init(void) { /* 在 0 到 100 之间随机一个数字 */ php_random_int(0, 100, &rnd, 0); } PHP_RINIT_FUNCTION(pib) { pib_rnd_init(); return SUCCESS; } PHP_FUNCTION(pib_guess) { zend_long r; if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &r) == FAILURE) { return; } if (r == rnd) { /* 将数字重置以进行猜测 */ pib_rnd_init(); RETURN_TRUE; } if (r < rnd) { RETURN_STRING("more"); } RETURN_STRING("less"); } PHP_FUNCTION(pib_reset) { if (zend_parse_parameters_none() == FAILURE) { return; } pib_rnd_init(); }
ご覧のとおり、この拡張機能はリクエストの先頭でランダムな整数を選択し、pib_guess()
を通じて配列を推測しようとします。推測されると、番号はリセットされます。ユーザーが数値を手動でリセットしたい場合は、pib_reset()
を手動で呼び出して値をリセットすることもできます。
乱数は C グローバル変数 として実装されます。 PHP がマルチプロセス モデルの一部としてインプロセスで使用される場合は問題になりませんが、後でスレッドが使用される場合は、これは問題ありません。
NOTE
注意事項として、どのマルチプロセス モデルを使用するかを知る必要はありません。拡張機能を設計するときは、両方のモデルに対応できるように準備する必要があります。
スレッドを使用する場合、C グローバル変数はサーバー内のスレッドごとに共有されます。たとえば、上記の例では、ネットワーク サーバーの各同時ユーザーは同じ値を共有します。最初に値をリセットする人もいますが、推測しようとする人もいます。つまり、スレッドに関する重要な問題を明確に理解できたということです。
同じリクエストに対してデータを永続化する必要があります。実行中の PHP のマルチプロセス モデルがスレッドを利用する場合でも、現在のリクエストに バインドする必要があります。
TSRM マクロを使用してグローバル領域を保護する
PHP は、拡張機能およびカーネル開発者がグローバル リクエストを処理するのに役立つレイヤーを備えて設計されています。この層は TSRM (スレッドセーフ リソース管理) と呼ばれ、リクエスト バインドされたグローバル (読み取りおよび書き込み) にアクセスする必要がある場合に常に使用する必要があるマクロのセットとして公開されます。
プロセスを使用するマルチプロセス モデルの場合、これらのマクロはバックグラウンドで解析されて、上で示したものと同様のコードになります。ご覧のとおり、スレッドを使用しない場合、上記のコードは完全に有効です。したがって、プロセスを使用する場合、これらのマクロは同様のマクロに展開されます。
最初に行う必要があるのは、すべてのグローバル変数のルートとなる構造体を宣言することです:
ZEND_BEGIN_MODULE_GLOBALS(pib) zend_long rnd; ZEND_END_MODULE_GLOBALS(pib) /* 解析为 : * * typedef struct _zend_pib_globals { * zend_long rnd; * } zend_pib_globals; */
次に、次のようなグローバル変数を作成します:
ZEND_DECLARE_MODULE_GLOBALS(pib) /* 解析为 zend_pib_globals pib_globals; */
これで、グローバル マクロ アクセサーを使用してデータにアクセスできるようになります。このマクロはフレームワークによって作成され、php_pib.h ヘッダー ファイルで定義する必要があります。これは次のようになります:
#ifdef ZTS #define PIB_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(pib, v) #else #define PIB_G(v) (pib_globals.v) #endif
ご覧のとおり、ZTS モードが有効になっていない場合、つまり非スレッドセーフな PHP と拡張機能をコンパイルしている場合 (これを NTS モード: 非スレッドと呼びます)安全)、マクロは単に構造体で宣言されたデータに解決されます。したがって、次の変更があります。
static void pib_rnd_init(void) { php_random_int(0, 100, &PIB_G(rnd), 0); } PHP_FUNCTION(pib_guess) { zend_long r; if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &r) == FAILURE) { return; } if (r == PIB_G(rnd)) { pib_rnd_init(); RETURN_TRUE; } if (r < PIB_G(rnd)) { RETURN_STRING("more"); } RETURN_STRING("less"); }
Note
プロセス モデルを使用する場合、TSRM マクロは C グローバル変数へのアクセスを解決します。
スレッドを使用する場合、つまり ZTS PHP をコンパイルする場合、状況はさらに複雑になります。次に、私たちが目にするすべてのマクロは、まったく異なるものに解決されますが、これをここで説明するのは困難です。基本的に、TSRM は、ZTS でコンパイルされると、TLS (スレッド ローカル ストレージ) を使用して難しい仕事を行います。
NOTE
つまり、ZTS でコンパイルすると、グローバル変数は現在のスレッドにバインドされます。 NTS をコンパイルするとき、グローバル変数は現在のプロセスにバインドされます。 TSRM マクロは難しい作業を処理します。これがどのように機能するかに興味があり、PHP ソース コードの /TSRM ディレクトリを参照して、PHP スレッド セーフの詳細を確認してください。
在扩展中使用全局钩子
有时,可能需要将全局变量初始化为一些默认值,通常为零。引擎帮助下的TSRM系统提供了一个钩子来为您的全局变量提供默认值,我们称之为GINIT。
注意
关于 PHP 挂钩的完整信息,请参考 PHP 生命周期章节。
让我们将随机值设为零:
PHP_GSHUTDOWN_FUNCTION(pib) { } PHP_GINIT_FUNCTION(pib) { pib_globals->rnd = 0; } zend_module_entry pib_module_entry = { STANDARD_MODULE_HEADER, "pib", NULL, NULL, NULL, NULL, NULL, NULL, "0.1", PHP_MODULE_GLOBALS(pib), PHP_GINIT(pib), PHP_GSHUTDOWN(pib), NULL, /* PRSHUTDOWN() */ STANDARD_MODULE_PROPERTIES_EX };
我们选择仅显示 zend_module_entry
(和其他 NULL
)的相关部分。如你所见,全局管理挂钩发生在结构的中间。首先是PHP_MODULE_GLOBALS()
来确定全局变量的大小,然后是我们的 GINIT
和 GSHUTDOWN
钩子。然后我们使用了STANDARD_MODULE_PROPERTIES_EX
关闭结构,而不是STANDARD_MODULE_PROPERTIES
。只需以正确的方式完成结构即可,请参阅?:
#define STANDARD_MODULE_PROPERTIES NO_MODULE_GLOBALS, NULL, STANDARD_MODULE_PROPERTIES_EX
在GINIT
函数中,你传递了一个指向全局变量当前存储位置的指针。你可以使用它来初始化全局变量。在这里,我们将零放入随机值(虽然不是很有用,但我们接受它)。
警告
不要在 GINIT 中使用
PIB_G()
宏。使用你得到的指针。注意
对于当前进程,在
MINIT()
之前启动了GINIT()
。如果是 NTS,就这样而已。 如果是 ZTS,线程库产生的每个新线程都会额外调用GINIT()
。警告
GINIT()
不作为RINIT()
的一部分被调用。如果你需要在每次新请求时清除全局变量,则需要像在本章所示示例中所做的那样手动进行。
完整的例子
这是一个更高级的完整示例。如果玩家获胜,则将其得分(尝试次数)添加到可以从用户区获取的得分数组中。没什么难的,得分数组在请求启动时初始化,然后在玩家获胜时使用,并在当前请求结束时清除:
ZEND_BEGIN_MODULE_GLOBALS(pib) zend_long rnd; zend_ulong cur_score; zval scores; ZEND_END_MODULE_GLOBALS(pib) ZEND_DECLARE_MODULE_GLOBALS(pib) static void pib_rnd_init(void) { /* 重置当前分数 */ PIB_G(cur_score) = 0; php_random_int(0, 100, &PIB_G(rnd), 0); } PHP_GINIT_FUNCTION(pib) { /* ZEND_SECURE_ZERO 是 memset(0)。也可以解析为 bzero() */ ZEND_SECURE_ZERO(pib_globals, sizeof(*pib_globals)); } ZEND_BEGIN_ARG_INFO_EX(arginfo_guess, 0, 0, 1) ZEND_ARG_INFO(0, num) ZEND_END_ARG_INFO() PHP_RINIT_FUNCTION(pib) { array_init(&PIB_G(scores)); pib_rnd_init(); return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(pib) { zval_dtor(&PIB_G(scores)); return SUCCESS; } PHP_FUNCTION(pib_guess) { zend_long r; if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &r) == FAILURE) { return; } if (r == PIB_G(rnd)) { add_next_index_long(&PIB_G(scores), PIB_G(cur_score)); pib_rnd_init(); RETURN_TRUE; } PIB_G(cur_score)++; if (r < PIB_G(rnd)) { RETURN_STRING("more"); } RETURN_STRING("less"); } PHP_FUNCTION(pib_get_scores) { if (zend_parse_parameters_none() == FAILURE) { return; } RETVAL_ZVAL(&PIB_G(scores), 1, 0); } PHP_FUNCTION(pib_reset) { if (zend_parse_parameters_none() == FAILURE) { return; } pib_rnd_init(); } static const zend_function_entry func[] = { PHP_FE(pib_reset, NULL) PHP_FE(pib_get_scores, NULL) PHP_FE(pib_guess, arginfo_guess) PHP_FE_END }; zend_module_entry pib_module_entry = { STANDARD_MODULE_HEADER, "pib", func, /* 函数入口 */ NULL, /* 模块初始化 */ NULL, /* 模块关闭 */ PHP_RINIT(pib), /* 请求初始化 */ PHP_RSHUTDOWN(pib), /* 请求关闭 */ NULL, /* 模块信息 */ "0.1", /* 替换为扩展的版本号 */ PHP_MODULE_GLOBALS(pib), PHP_GINIT(pib), NULL, NULL, STANDARD_MODULE_PROPERTIES_EX };
这里必须要注意的是,如果你希望在请求之间保持分数,PHP 不提供任何便利。而是需要一个持久的共享存储,例如文件,数据库,某些内存区域等。PHP 的设计目的不是将信息持久存储在其内部的请求,因此它不提供这么做,但它提供了实用程序来访问请求绑定的全局空间,如我们所示。
然后,很容易地在RINIT()
中初始化一个数组,然后在RSHUTDOWN()
中销毁它。请记住,array_init
创建一个zend_array 并放入一个 zval。但这是免分配的,不要担心分配用户无法使用的数组(因此浪费分配),array_init()
非常廉价 (阅读源代码)。
当我们将这样的数组返回给用户时,我们不会忘记增加其引用计数(在 RETVAL_ZVAL
中),因为我们在扩展中保留了对此类数组的引用。
使用真实的全局变量
真实全局变量是非线程保护的真实C全局变量。有时可能会需要它们。但是请记住主要规则:在处理请求时,不能安全地写入此类全局变量。因此,通常在 PHP 中,我们需要此类变量并将其用作只读变量。
请记住,在 PHP 生命周期的MINIT()
或MSHUTDOWN()
步骤中编写真实全局变量是绝对安全的。但是不能在处理请求时给他们写入值(但可以从他们那里读取)。
因此,一个简单的示例是你想要读取环境值以对其进行处理。此外,初始化持久性的 zend_string并在之后处理某些请求时加以利用是很常见的。
这是介绍真实全局变量的修补示例,我们仅显示与先前代码的差异,而不显示完整代码:
static zend_string *more, *less; static zend_ulong max = 100; static void register_persistent_string(char *str, zend_string **result) { *result = zend_string_init(str, strlen(str), 1); zend_string_hash_val(*result); GC_FLAGS(*result) |= IS_INTERNED; } static void pib_rnd_init(void) { /* 重置当前分数 */ PIB_G(cur_score) = 0; php_random_int(0, max, &PIB_G(rnd), 0); } PHP_MINIT_FUNCTION(pib) { char *pib_max; register_persistent_string("more", &more); register_persistent_string("less", &less); if (pib_max = getenv("PIB_RAND_MAX")) { if (!strchr(pib_max, '-')) { max = ZEND_STRTOUL(pib_max, NULL, 10); } } return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(pib) { zend_string_release(more); zend_string_release(less); return SUCCESS; } PHP_FUNCTION(pib_guess) { zend_long r; if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &r) == FAILURE) { return; } if (r == PIB_G(rnd)) { add_next_index_long(&PIB_G(scores), PIB_G(cur_score)); pib_rnd_init(); RETURN_TRUE; } PIB_G(cur_score)++; if (r < PIB_G(rnd)) { RETURN_STR(more); } RETURN_STR(less); }
在这里我们创建了两个 zend_string 变量 more
和 less
。这些字符串不需要像以前一样在使用时立即创建和销毁。这些是不可变的字符串,只要保持不变,就可以分配一次并在需要的任何时间重复使用(即只读)。我们在zend_string_init()
中使用持久分配,在MINIT()
中初始化这两个字符串,我们现在预先计算其哈希值(而不是先执行第一个请求),并且我们告诉 zval 垃圾收集器,这些字符串已被扣留,因此它将永远不会尝试销毁它们(但是,如果将它们用作写操作(例如连接)的一部分,则可能需要复制它们)。显然我们不会忘记在MSHUTDOWN()
中销毁这些字符串。
次に、MINIT()
で PIB_RAND_MAX
環境を調べ、それを乱数選択の最大範囲値として使用します。符号なし整数を使用しており、strtoull()
が負の数値について文句を言わないことがわかっているため (したがって、整数の範囲を符号の不一致としてラップします)、負の数値の使用を避けるだけです (古典的な libc 回避策)。
以上がPHP はグローバルステータスを管理しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

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

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

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

ホットトピック









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

あなたが経験豊富な PHP 開発者であれば、すでにそこにいて、すでにそれを行っていると感じているかもしれません。あなたは、運用を達成するために、かなりの数のアプリケーションを開発し、数百万行のコードをデバッグし、大量のスクリプトを微調整してきました。

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

JWTは、JSONに基づくオープン標準であり、主にアイデンティティ認証と情報交換のために、当事者間で情報を安全に送信するために使用されます。 1。JWTは、ヘッダー、ペイロード、署名の3つの部分で構成されています。 2。JWTの実用的な原則には、JWTの生成、JWTの検証、ペイロードの解析という3つのステップが含まれます。 3. PHPでの認証にJWTを使用する場合、JWTを生成および検証でき、ユーザーの役割と許可情報を高度な使用に含めることができます。 4.一般的なエラーには、署名検証障害、トークンの有効期限、およびペイロードが大きくなります。デバッグスキルには、デバッグツールの使用とロギングが含まれます。 5.パフォーマンスの最適化とベストプラクティスには、適切な署名アルゴリズムの使用、有効期間を合理的に設定することが含まれます。

このチュートリアルでは、PHPを使用してXMLドキュメントを効率的に処理する方法を示しています。 XML(拡張可能なマークアップ言語)は、人間の読みやすさとマシン解析の両方に合わせて設計された多用途のテキストベースのマークアップ言語です。一般的にデータストレージに使用されます

文字列は、文字、数字、シンボルを含む一連の文字です。このチュートリアルでは、さまざまな方法を使用してPHPの特定の文字列内の母音の数を計算する方法を学びます。英語の母音は、a、e、i、o、u、そしてそれらは大文字または小文字である可能性があります。 母音とは何ですか? 母音は、特定の発音を表すアルファベットのある文字です。大文字と小文字など、英語には5つの母音があります。 a、e、i、o、u 例1 入力:string = "tutorialspoint" 出力:6 説明する 文字列「TutorialSpoint」の母音は、u、o、i、a、o、iです。合計で6元があります

静的結合(静的::) PHPで後期静的結合(LSB)を実装し、クラスを定義するのではなく、静的コンテキストで呼び出しクラスを参照できるようにします。 1)解析プロセスは実行時に実行されます。2)継承関係のコールクラスを検索します。3)パフォーマンスオーバーヘッドをもたらす可能性があります。

PHPの魔法の方法は何ですか? PHPの魔法の方法には次のものが含まれます。1。\ _ \ _コンストラクト、オブジェクトの初期化に使用されます。 2。\ _ \ _リソースのクリーンアップに使用される破壊。 3。\ _ \ _呼び出し、存在しないメソッド呼び出しを処理します。 4。\ _ \ _ get、dynamic属性アクセスを実装します。 5。\ _ \ _セット、動的属性設定を実装します。これらの方法は、特定の状況で自動的に呼び出され、コードの柔軟性と効率を向上させます。
