PHPのini設定を深く理解する(1)
特定の ini 設定項目の目的については、マニュアルで詳しく説明されていますが、この記事では詳しく説明しません。私は PHP の実装メカニズムを特定の観点から掘り下げたいだけですが、これには PHP カーネルの知識が必要になります:-)
PHP を使用する生徒は、php.ini 設定が SAPI ライフサイクル全体を通じて有効になることを知っています。 PHP スクリプトの実行中に、ini 設定を手動で変更しても、その変更は有効になりません。現時点で Apache または nginx を再起動できない場合は、php コードで ini_set インターフェイスを明示的に呼び出すことしかできません。 ini_set は、動的に設定を変更するために PHP が提供する関数です。ini_set で設定した設定と、ini ファイルに設定した設定は、有効な時間範囲が異なることに注意してください。 php スクリプトを実行すると、ini_set 設定はすぐに無効になります。
この記事は 2 つの部分に分かれており、最初の部分では php.ini 設定の原理について説明し、2 番目の部分では php 設定の動的変更について説明します。
php.iniの設定には大きく分けてconfiguration_hash、EG(ini_directives)、PG、BG、PCRE_G、JSON_G、XXX_Gなどの3つのデータが含まれます。これら 3 種類のデータの意味が分からなくても問題ありません。後で詳しく説明します。
1.INI設定ファイルを解析する
php.ini は SAPI プロセス全体で有効である必要があるため、ini ファイルを解析し、それに応じて php 設定を構築する作業が SAPI の始まりでなければなりません。つまり、PHP の起動プロセス中に発生する必要があります。 PHP では、実際のリクエストが到着する前に、これらの構成が内部で生成されている必要があります。
php_module_startup関数であるphpのコアに反映されます。
php_module_startup は主に php の起動を担当し、通常は SAPI の起動時に呼び出されます。ところで、もう 1 つの一般的な関数は php_request_startup です。これは、各リクエストが到着したときに初期化する役割を果たします。php_module_startup と php_request_startup は 2 つの象徴的なアクションですが、それらの分析はこの記事の範囲外です。
たとえば、php が Apache のモジュールにフックされている場合、Apache が起動すると、php モジュールを含むすべてのモジュールがアクティブ化されます。 PHPモジュールを有効化する際には、php_module_startupが呼び出されます。 php_module_startup 関数は、php_module_startup 呼び出しが終了すると、多くの作業を完了します。これは、php が開始され、リクエストを受け入れて応答できることを意味します。
php_module_startup 関数では、ini ファイルの解析に関連する実装は次のとおりです:
/* これは php.ini に読み込まれ、設定パラメータを設定します。
Zend 拡張機能をロードし、PHP 関数拡張機能を登録します
後でロードされます */
if (php_init_config(TSRMLS_C) == 失敗) {
失敗を返す;
}
ini ファイルの解析を完了するために php_init_config 関数が実際に呼び出されていることがわかります。解析作業は主に字句と文法の解析を実行し、キーと値のペアを抽出して ini ファイルに保存します。 php.ini の形式は非常に単純で、等号の左側にキー、右側に値があります。 KV のペアが抽出されるたびに、php はそれらをどこに保存しますか?答えは、前述したconfiguration_hashです。
静的ハッシュテーブル構成_ハッシュ;
Configuration_hash は php_ini.c で宣言されており、HashTable 型のデータ構造です。名前が示すように、実際にはハッシュ テーブルです。余談ですが、configuration_hash は php_ini.c ファイル内の静的変数であるため、php5.3 より前のバージョンでは取得できません。その後、php5.3 では、&configuration_hash を直接返す php_ini_get_configuration_hash インターフェイスが追加されました。これにより、さまざまな PHP 拡張機能で、configuration_hash を簡単に確認できるようになりました... なんとありがたいことでしょう...
4つのポイントに注意してください:
まず、php_init_config は字句と構文以外の検証を行いません。つまり、ini ファイルに行 hello=world を追加すると、これが正しくフォーマットされた構成項目である限り、最終的なconfiguration_hash にはキー hello と値 world を持つ要素が含まれ、configuration_hash はそれを反映します。 ini ファイルを最大限に拡張します。
2 番目に、ini ファイルを使用すると、配列の形式で構成できます。たとえば、ini ファイルに次の 3 行を記述します。
ドリフト.arr[]=1
ドリフト.arr[]=2
ドリフト.arr[]=3
その後、最終的に生成されたconfiguration_hashテーブルには、キーdrift.arrを持つ要素があり、その値は3つの数値1、2、3を含む配列になります。これは非常に珍しい構成方法です。
第三に、php では、デフォルトの php.ini ファイル (正確には php-%s.ini) に加えて、追加の ini ファイルを構築することもできます。これらの ini ファイルは追加のディレクトリに配置されます。このディレクトリは、環境変数 PHP_INI_SCAN_DIR によって指定されます。php_init_config が php.ini を解析した後、このディレクトリを再度スキャンし、分析のためにディレクトリ内のすべての .ini ファイルを検索します。これらの追加の ini ファイルで生成された kv キーと値のペアも、configuration_hash に追加されます。
これは、場合によっては便利な機能ですが、php.ini に設定を混ぜたくない場合、別の ini を作成し、PHP_INI_SCAN_DIR を通じてその場所を PHP に指示できます。もちろん、その欠点も明らかであり、それをサポートするには追加の環境変数を設定する必要があります。より良い解決策は、開発者が拡張機能内で php_parse_user_ini_file または zend_parse_ini_file を呼び出して、対応する ini ファイルを解析することです。
4 番目に、configuration_hash ではキーは文字列ですが、値の型は何でしょうか?答えも文字列です (上記の非常に特殊な配列を除く)。具体的には以下のような構成になります。
display_errors = オン
log_errors = オフ
log_errors_max_len = 1024
最終的なconfiguration_hashに実際に保存されるキーと値のペアは次のとおりです:
キー: "display_errors"
値: "1"
キー: "log_errors"
ヴァル:「」
キー: "log_errors_max_len"
値: "1024"
log_errors に注意してください。保存される値は「0」でさえなく、実際の空の文字列です。また、log_errors_max_len は数値ではなく、1024 の文字列です。
分析のこの時点で、基本的に ini ファイルの解析に関連するすべてが明確に説明されました。簡単に要約すると:
1.ini の解析は php_module_startup ステージで行われます
2. 解析結果はconfiguration_hashに保存されます。
2. 構成はモジュールに適用されます
PHP の一般的な構造は、OS との対話、PHP コードのコンパイル、メモリ ホスティングの提供などを担当する最下部の zend エンジンとして見ることができます。zend エンジンの上位層には多くのモジュールが配置されています。コアモジュールは Core モジュールで、その他には Standard、PCRE、Date、Session などがあります。これらのモジュールには、php 拡張機能と呼ばれる別の名前もあります。各モジュールは、開発者が呼び出すための一連の関数インターフェイスを提供していることを簡単に理解できます。たとえば、explode、trim、array などの一般的に使用される組み込み関数は、Standard モジュールによって提供されます。
これらについて説明する必要がある理由は、php.ini には、php 自体、つまりコア モジュールの設定 (safe_mode、display_errors、max_execution_time など) に加えて、かなりの数の設定があるためです。他の異なるモジュールの場合。
たとえば、一般的な日付、時刻、strtotime、その他の関数を提供する date モジュールです。 php.ini では、関連する設定は次のようになります:
[日付]
;date.timezone = 'アジア/上海'
;日付.default_latitude = 31.7667
;date.default_longitude = 35.2333
;日付.sunrise_zenith = 90.583333
;日付.sunset_zenith = 90.583333
これらのモジュールが独立した構成を持つことに加えて、zend エンジンも構成可能ですが、zend エンジンには構成可能な項目が非常に少なく、error_reporting、zend.enable_gc、および detect_unicode のみです。
前のセクションで、php_module_startup が php_init_config を呼び出すことをすでに述べました。その目的は、ini ファイルを解析し、configuration_hash を生成することです。それでは、次に php_module_startup で他に何が行われるのでしょうか?明らかに、configuration_hash の設定は、Zend、Core、Standard、SPL などのさまざまなモジュールに適用されます。もちろん、PHP には通常多くのモジュールが含まれており、これらのモジュールも PHP の起動中に順番に開始されるため、これは一晩で完了するプロセスではありません。次に、モジュール A の起動プロセス中に、モジュール A を構成するプロセスが発生します。
拡張機能開発の経験のある学生は、モジュール A が PHP_MINIT_FUNCTION(A) で開始されていることを直接指摘しますよね。
はい、モジュール A を設定する必要がある場合は、PHP_MINIT_FUNCTION で REGISTER_INI_ENTRIES() を呼び出して設定を完了できます。 REGISTER_INI_ENTRIES は、現在のモジュールに必要な構成項目の名前に基づいて、ユーザーが設定した構成値のconfiguration_hash を検索し、それをモジュール独自のグローバル空間に更新します。
2.1、モジュールのグローバル空間
configuration_hash から各モジュールに ini 設定を適用する方法を理解するには、まず PHP モジュールのグローバル空間を理解する必要があります。さまざまな PHP モジュールに対して、独自のストレージ スペースを開くことができ、このスペースはモジュールからグローバルに参照できます。一般に、モジュールに必要な ini 設定を保存するために使用されます。つまり、configuration_hash 内の構成アイテムは、最終的にはグローバル空間に保存されます。モジュールの実行中、このグローバル空間に直接アクセスしてモジュールのユーザー設定を取得するだけで済みます。もちろん、モジュールの実行中に中間データを記録するためにもよく使用されます。
bcmath モジュールを例に挙げてみましょう。bcmath は数学的計算のためのインターフェイスを提供する php モジュールです。まず、その ini 設定を見てみましょう。
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
PHP_INI_END()
bcmath には 1 つの設定項目しかありません。php.ini の bcmath.scale を使用して bcmath モジュールを設定できます。
次に、bcmatch モジュールのグローバル空間定義を見てみましょう。 php_bcmath.h には次のステートメントがあります:
ZEND_BEGIN_MODULE_GLOBALS(bcmath)
bc_num _zero_;
bc_num _one_;
bc_num _two_;
長い bc_precision;
ZEND_END_MODULE_GLOBALS(bcmath)
マクロを展開すると、次のようになります:
typedef struct _zend_bcmath_globals {
bc_num _zero_;
bc_num _one_;
bc_num _two_;
長い bc_precision;
} zend_bcmath_globals;
実際には、zend_bcmath_globals タイプは bcmath モジュールのグローバル空間タイプです。ここでは zend_bcmath_globals 構造のみが宣言されており、bcmath.c には特定のインスタンス化定義もあります。
// 展開後は、zend_bcmath_globals bcmath_globals;
ZEND_DECLARE_MODULE_GLOBALS(bcmath)
変数bcmath_globalsの定義がZEND_DECLARE_MODULE_GLOBALSで完了していることがわかります。
bcmath_globals は、4 つのフィールドを含む実際のグローバル空間です。最後のフィールド bc_precision は、ini 設定の bcmath.scale に対応します。 php.ini で bcmath.scale の値を設定し、bcmath モジュールの起動時に bcmath.scale の値が bcmath_globals.bc_precision に更新されます。
configuration_hash の値を各モジュールで定義された xxx_globals 変数に更新します。これは、いわゆる ini 設定をモジュールに適用することです。モジュールが開始されると、これらの構成が設定されます。したがって、後続の実行フェーズでは、php モジュールは、configuration_hash に再度アクセスする必要はなく、ユーザーが設定した構成を取得するために独自の XXX_globals にアクセスするだけで済みます。
bcmath_globals、ini 設定項目の 1 つのフィールドに加えて、他の 3 つのフィールドは何ですか?これはモジュールのグローバル空間の 2 番目の役割であり、ini 構成に使用されるだけでなく、モジュールの実行中に一部のデータを保存することもできます。
もう 1 つの例は json モジュールです。これも PHP で非常によく使用されるモジュールです。
ZEND_BEGIN_MODULE_GLOBALS(json)
int error_code;
ZEND_END_MODULE_GLOBALS(json)
json モジュールには ini 設定が必要なく、そのグローバル空間には error_code フィールドが 1 つだけあることがわかります。 error_code は、json_decode または json_encode の最後の実行で発生したエラーを記録します。 json_last_error 関数はこの error_code を返し、ユーザーがエラーの原因を特定できるようにします。
モジュールのグローバル空間変数に簡単にアクセスするために、PHP は従来からいくつかのマクロを提案してきました。たとえば、json_globals の error_code にアクセスしたい場合は、もちろん json_globals.error_code として直接記述することもできますが (マルチスレッド環境では使用できません)、より一般的な記述方法は、JSON_G マクロを定義することです。
#define JSON_G(v) (json_globals.v)
JSON_G(error_code) を使用して json_globals.error_code にアクセスします。この記事の冒頭で、PG、BG、JSON_G、PCRE_G、XXX_G などについて触れました。これらのマクロは、PHP ソース コードでも非常に一般的です。これで、PG マクロは Core モジュールのグローバル変数にアクセスでき、BG は Standard モジュールのグローバル変数にアクセスでき、PCRE_G は PCRE モジュールのグローバル変数にアクセスできることが簡単に理解できます。
#define PG(v) (core_globals.v)
#define BG(v) (basic_globals.v)
2.2. モジュールに必要な構成を決定するにはどうすればよいですか?
モジュールがどのような種類の INI 設定を必要とするかは、各モジュールで定義されます。たとえば、Core モジュールの場合、次の構成項目の定義があります:
PHP_INI_BEGIN()
…
STD_PHP_INI_ENTRY_EX("display_errors", "1"、PHP_INI_ALL、OnUpdateDisplayErrors、display_errors、php_core_globals、core_globals、display_errors_mode)
STD_PHP_INI_BOOLEAN("enable_dl", "1", PHP_INI_SYSTEM, OnUpdateBool, enable_dl, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("expose_php", "1", PHP_INI_SYSTEM, OnUpdateBool, Expose_php, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("safe_mode", "0", PHP_INI_SYSTEM, OnUpdateBool,safe_mode, php_core_globals, core_globals)
…
PHP_INI_END()
上記のコードは、php-srcmainmain.c ファイルの約 450 行以上にあります。 ZEND_INI_BEGIN、ZEND_INI_END、PHP_INI_ENTRY_EX、STD_PHP_INI_BOOLEAN など、多くのマクロが関係しています。この記事では詳しく説明しませんので、興味のある読者はご自身でマクロを分析してください。
上記のコードをマクロ展開すると、次のようになります:
static const zend_ini_entry ini_entries[] = {
..
{ 0, PHP_INI_ALL, "display_errors",sizeof("display_errors"),OnUpdateDisplayErrors,(void *)XtOffsetOf(php_core_globals, display_errors), (void *)&core_globals, NULL, "1", sizeof("1")-1 、NULL、0、0、0、display_errors_mode }、
{ 0、PHP_INI_SYSTEM、"enable_dl"、sizeof("enable_dl")、OnUpdateBool、(void *)XtOffsetOf(php_core_globals、enable_dl)、(void *)&core_globals、NULL、"1"、sizeof("1")- 1 、NULL、0、0、0、zend_ini_boolean_displayer_cb }、
{ 0, PHP_INI_SYSTEM, "expose_php", sizeof("expose_php"), OnUpdateBool, (void *)XtOffsetOf(php_core_globals, Expose_php), (void *)&core_globals, NULL, "1", sizeof("1")-1 、NULL、0、0、0、zend_ini_boolean_displayer_cb }、
{ 0、PHP_INI_SYSTEM、"safe_mode"、sizeof("safe_mode")、OnUpdateBool、(void *)XtOffsetOf(php_core_globals、safe_mode)、(void *)&core_globals、NULL、"0"、sizeof("0")-1 、NULL、0、0、0、zend_ini_boolean_displayer_cb }、
...
{ 0、0、NULL、0、NULL、NULL、NULL、NULL、NULL、0、NULL、0、0、0、NULL }
};
構成アイテムの定義は基本的に zend_ini_entry 型の配列を定義していることがわかります。 zend_ini_entry 構造体のフィールドの具体的な意味は次のとおりです:
struct _zend_ini_entry {
int module_number // モジュール ID
int modifiable; // php.ini、ini_set などの変更可能な範囲
Char *名前;
uint name_length;
ZEND_INI_MH((*on_modify)); // コールバック関数、構成アイテムが登録または変更されるときに呼び出されます
void *mh_arg1; // 通常は XXX_G の構成項目フィールドのオフセット
void *mh_arg2; // 通常は XXX_G
void *mh_arg3; // 通常は予約されたフィールドですが、ほとんど使用されません
文字 *値;
uint value_length;
char *orig_value; // 設定項目の元の値
uint orig_value_length;
int orig_modifiable; // 構成アイテムの元の変更可能要素
int 変更済み;
void (*displayer)(zend_ini_entry *ini_entry, int 型);
};
2.3、構成をモジュールに適用します—REGISTER_INI_ENTRIES
さまざまな拡張機能の PHP_MINIT_FUNCTION で REGISTER_INI_ENTRIES がよく見られます。 REGISTER_INI_ENTRIES は主に 2 つのことを完了する役割を果たします。1 つは、モジュールのグローバル空間 XXX_G を埋めることと、configuration_hash の値を XXX_G に同期することです。次に、EG(ini_directives) も生成します。
REGISTER_INI_ENTRIES もマクロです。展開後は、実際には zend_register_ini_entries メソッドになります。 zend_register_ini_entries の実装を具体的に見てみましょう:
ZEND_API int zend_register_ini_entries(const zend_ini_entry *ini_entry, int module_number TSRMLS_DC) /* {{{ */
{
// ini_entry は zend_ini_entry 型の配列であり、p は配列内の各項目のポインタです
const zend_ini_entry *p = ini_entry;
zend_ini_entry *hashed_ini_entry;
zval デフォルト値;
// EG(ini_directives) は registered_zend_ini_directives です
ハッシュテーブル *ディレクティブ = registered_zend_ini_directives;
zend_bool config_directive_success = 0;
// ini_entry の最後の項目は {0, 0, NULL, ...} に固定されていることを覚えていますか
while (p->name) {
config_directive_success = 0;
// p が指す zend_ini_entry を EG (ini_directives) に追加します
if (zend_hash_add(directives, p->name, p->name_length, (void*)p, sizeof(zend_ini_entry), (void **) &hashed_ini_entry) == FAILURE) {
zend_unregister_ini_entries(module_number TSRMLS_CC);
失敗を返す;
}
hashed_ini_entry->モジュール番号 = モジュール番号;
// 名前に基づいてconfiguration_hashでクエリを実行し、結果をdefault_valueに入れます
//default_value の値は、php.ini での記述方法に応じて、通常は数値、文字列、配列などの比較的原始的なものであることに注意してください
if ((zend_get_configuration_directive(p->name, p->name_length, &default_value)) == SUCCESS) {
// on_modify を呼び出してモジュールのグローバル空間 XXX_G を更新します
if (!hashed_ini_entry->on_modify || hashed_ini_entry->on_modify(hashed_ini_entry, Z_STRVAL(default_value), Z_STRLEN(default_value), hashed_ini_entry->mh_arg1, hashed_ini_entry->mh_ g2、hashed_ini_entry->mh_arg3、ZEND_INI_STAGE_STARTUP TSRMLS_CC ) ==成功) {
hashed_ini_entry->value = Z_STRVAL(default_value);
hashed_ini_entry->value_length = Z_STRLEN(default_value);
D Config_directive_success = 1;
}
}
//configuration_hash に見つからない場合は、デフォルト値が使用されます
if (!config_directive_success && hashed_ini_entry->on_modify) {
hashed_ini_entry->on_modify(hashed_ini_entry, hashed_ini_entry->value, hashed_ini_entry->value_length, hashed_ini_entry->mh_arg1, hashed_ini_entry->mh_arg2, hashed_ini_entry-> t;mh_arg3、ZEND_INI_STAGE_STARTUP TSRMLS_CC);
}
p++;
}
成功を返します;
}
簡単に言えば、上記のコードのロジックは次のように表現できます:
1. モジュールで宣言したini設定項目をEG(ini_directives)に追加します。 ini 設定項目の値は後で変更される可能性があることに注意してください。
2. 各モジュールに必要なiniをconfiguration_hashで見つけてください。
それが見つかった場合は、この値がユーザーの ini ファイルで構成されており、ユーザーの構成が使用されることを意味します。
それが見つからない場合でも、モジュールは ini を宣言するときにデフォルト値を取得するため、問題ありません。
3.iniの値をXX_Gに同期します。結局のところ、php の実行中、これらの XXX_global は依然として役割を果たします。具体的な処理は、ini の宣言時にモジュールで指定された各 ini 設定に対応する on_modify メソッドを呼び出します。
実際には関数ポインターである on_modify を詳しく見てみましょう。2 つの特定のコア モジュールの構成ステートメントを見てみましょう。
STD_PHP_INI_BOOLEAN("log_errors", "0", PHP_INI_ALL, OnUpdateBool, log_errors, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("log_errors_max_len","1024", PHP_INI_ALL, OnUpdateLong, log_errors_max_len, php_core_globals, core_globals)
log_errors の場合、その on_modify は OnUpdateBool に設定され、log_errors_max_len の場合、その on_modify は OnUpdateLong に設定されます。
さらに、php.ini の設定が次のようになっていると仮定します。
log_errors = オン
log_errors_max_len = 1024
OnUpdateBool 関数を詳しく見てみましょう:
ZEND_API ZEND_INI_MH(OnUpdateBool)
{
zend_bool *p;
// Base は core_globals のアドレスを表します
char *base = (char *) mh_arg2;
// p は core_globals のアドレスに log_errors フィールドのオフセットを加えたものを表します
//取得したアドレスはlog_errorsフィールドのアドレスです
p = (zend_bool *) (base+(size_t) mh_arg1);
if (new_value_length == 2 && strcasecmp("on", new_value) == 0) {
*p = (zend_bool) 1;
}
else if (new_value_length == 3 && strcasecmp("yes", new_value) == 0) {
*p = (zend_bool) 1;
}
else if (new_value_length == 4 && strcasecmp("true", new_value) == 0) {
*p = (zend_bool) 1;
}
その他 {
//configuration_hash に格納される値は文字列「1」であり、「On」ではありません
roiしたがって、アトイを使用してそれを数字1に変換する
*p = (zend_bool) atoi(new_value);
}
成功を返します;
}
最も不可解なものは、おそらく mh_arg1 と mh_arg2 です。実際、前述の zend_ini_entry の定義に基づくと、mh_arg1 と mh_arg2 はまだ理解しやすいです。 mh_arg1 はバイト オフセットを表し、mh_arg2 は XXX_globals のアドレスを表します。したがって、(char *)mh_arg2 + mh_arg1 の結果は、XXX_globals のフィールドのアドレスになります。この場合、具体的には、core_globals 内の log_errors のアドレスを計算します。したがって、OnUpdateBool が最終的に実行されると
*p = (zend_bool) atoi(new_value);
その機能は
と同等です
core_globals.log_errors = (zend_bool) atoi("1");
OnUpdateBool を分析した後、OnUpdateLong を見てみましょう。それは一目瞭然です:
ZEND_API ZEND_INI_MH(OnUpdateLong)
{
長い*p;
char *base = (char *) mh_arg2;
// log_errors_max_len のアドレスを取得します
p = (long *) (base+(size_t) mh_arg1);
//「1024」をlong型に変換してcore_globals.log_errors_max_lenに代入する
*p = zend_atol(new_value, new_value_length);
成功を返します;
}
最後に注意すべきことは、zend_register_ini_entries 関数では、configuration_hash に設定がある場合、on_modify が呼び出されたときに hashed_ini_entry の value と value_length が更新されるということです。つまり、ユーザーが php.ini で設定した場合、EG (ini_directives) には実際の設定値が保存されます。ユーザーが設定されていない場合、EG (ini_directives) は zend_ini_entry の宣言時に指定されたデフォルト値を保存します。
zend_register_ini_entries のdefault_value 変数の名前が適切ではないため、誤解を招きやすいです。実際、default_value はデフォルト値を表すのではなく、ユーザーが実際に構成した値を表します。
3、まとめ
これで、configuration_hash、EG (ini_directives)、PG、BG、PCRE_G、JSON_G、XXX_G... の 3 つのデータがすべて明確に説明されました。
要約すると:
1、configuration_hash は、php.ini ファイルに設定を保存し、検証は実行せず、その値は文字列です。
2、EG (ini_directives) は、各モジュールで定義された zend_ini_entry を格納します。ユーザーが php.ini (configuration_hash に存在) で設定した場合、値はconfiguration_hash の値に置き換えられ、型は文字列のままです。
3、XXX_G、このマクロはモジュールのグローバル空間にアクセスするために使用されます。このメモリ空間は、ini 設定を保存するために使用され、on_modify で指定された関数を通じて更新されます。そのデータ型は、XXX_G のフィールド宣言によって決定されます。
http://www.bkjia.com/PHPjc/892830.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/892830.html技術記事 php の ini 設定を深く理解する (1) この記事では、特定の ini 設定項目の目的については詳しく説明しません。これらについてはマニュアルで十分に説明されています。ある角度から掘ってみたい…