>  기사  >  php教程  >  php_php 기초의 ini 구성 원리에 대한 자세한 설명

php_php 기초의 ini 구성 원리에 대한 자세한 설명

WBOY
WBOY원래의
2016-05-16 08:59:572129검색

PHP를 사용하는 학생들은 php.ini 구성이 전체 SAPI 수명 주기 동안 적용된다는 것을 알고 있습니다. PHP 스크립트를 실행하는 동안 ini 구성을 수동으로 수정하면 적용되지 않습니다. 지금 Apache 또는 nginx를 다시 시작할 수 없는 경우 PHP 코드에서 ini_set 인터페이스를 명시적으로 호출할 수만 있습니다. ini_set는 구성을 동적으로 수정하기 위해 PHP에서 제공하는 함수입니다. ini_set에 의해 설정된 구성과 ini 파일에 설정된 구성은 서로 다른 유효 시간 범위를 갖는다는 점에 유의해야 합니다. PHP 스크립트가 실행된 후 ini_set 설정은 즉시 무효화됩니다.

따라서 이 글은 두 부분으로 나누어 첫 번째 부분에서는 php.ini 구성의 원리를 설명하고, 두 번째 부분에서는 PHP 구성을 동적으로 수정하는 방법에 대해 설명합니다.

php.ini 구성에는 대략 구성_해시, EG(ini_directives), PG, BG, PCRE_G, JSON_G, XXX_G 등 세 가지 데이터가 포함됩니다. 이 세 가지 데이터 유형의 의미를 모르더라도 상관 없습니다. 아래에서 자세히 설명합니다.

1, INI 구성 파일 구문 분석

SAPI 프로세스 중에 php.ini가 적용되어야 하므로 ini 파일을 파싱하고 이에 따라 php 구성을 구축하는 작업이 SAPI의 시작이 되어야 합니다. 즉, PHP 시작 프로세스 중에 발생해야 합니다. PHP는 실제 요청이 도착하기 전에 내부적으로 이러한 구성을 생성해야 합니다.

php의 핵심인 php_module_startup 함수에 반영되었습니다.

php_module_startup은 주로 PHP 시작을 담당합니다. 일반적으로 SAPI가 시작될 때 호출됩니다. 그런데 또 다른 일반적인 함수는 php_request_startup으로, 각 요청이 도착할 때 초기화를 담당합니다. php_module_startup과 php_request_startup은 두 가지 상징적인 작업이지만 이에 대한 분석은 이 기사의 범위를 벗어납니다.

예를 들어, 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) == 실패) {
반품 실패;
}

보시다시피 php_init_config 함수는 실제로 ini 파일의 구문 분석을 완료하기 위해 호출됩니다. 구문 분석 작업은 주로 어휘&문법 분석을 수행하며, 키와 값 쌍을 추출하여 ini 파일에 저장합니다. php.ini의 형식은 매우 간단합니다. 등호 왼쪽에 키가 있고 오른쪽에 값이 있습니다. kv 쌍이 추출될 때마다 PHP는 이를 어디에 저장합니까? 대답은 앞서 언급한 Configuration_hash입니다.

정적 HashTable 구성_hash;
HashTable 형태의 자료구조인 php_ini.c에 Configuration_hash가 선언되어 있습니다. 이름에서 알 수 있듯이 실제로는 해시 테이블입니다. 여담이지만, 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 줄을 추가하면 이것이 올바른 형식의 구성 항목인 한 최종 구성_hash에는 hello 키와 world 값이 있는 요소가 포함되며,configuration_hash는 이를 반영합니다. ini 파일을 최대한 활용하세요.

둘째, ini 파일을 사용하면 배열 형태로 구성할 수 있습니다. 예를 들어, ini 파일에 다음 세 줄을 작성합니다.

코드 복사 코드는 다음과 같습니다.

drift.arr[]=1
drift.arr[]=2
drift.arr[]=3

그런 다음 최종 생성된 Configuration_hash 테이블에는 Drift.arr 키가 있는 요소가 있고 해당 값은 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 확장을 직접 개발하지만 구성을 php.ini에 혼합하고 싶지 않은 경우, 다른 ini를 작성하고 PHP_INI_SCAN_DIR을 통해 이를 찾을 수 있는 위치를 PHP에 알려줄 수 있습니다. 물론 단점도 분명하며, 이를 지원하려면 추가적인 환경 변수 설정이 필요합니다. 더 나은 해결책은 개발자가 확장에서 php_parse_user_ini_file 또는 zend_parse_ini_file을 직접 호출하여 해당 ini 파일을 구문 분석하는 것입니다.

넷째,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, php_module_startup 단계에서 ini 파싱이 발생합니다

2. 파싱 결과는 Configuration_hash에 저장됩니다.

2, 구성은 모듈에 적용됩니다.

PHP의 일반적인 구조는 하단의 zend 엔진으로 볼 수 있는데, 이는 OS와의 상호작용, PHP 코드 컴파일, 메모리 호스팅 제공 등을 담당합니다. zend 엔진의 상위 계층에는 여러 가지가 있습니다. 모듈이 배열되어 있습니다. 핵심 모듈은 Core 모듈이며 기타에는 Standard, PCRE, Date, Session 등이 포함됩니다. 이러한 모듈에는 php 확장이라는 또 다른 이름도 있습니다. 각 모듈은 개발자가 호출할 수 있는 일련의 기능적 인터페이스를 제공한다는 점만 이해하면 됩니다. 예를 들어 분해, 다듬기, 배열 등과 같이 일반적으로 사용되는 내장 기능은 표준 모듈에서 제공됩니다.

이에 대해 이야기해야 하는 이유는 php.ini에는 PHP 자체, 즉 핵심 모듈(예: safe_mode, display_errors, max_execution_time 등)에 대한 일부 구성 외에도 꽤 많은 구성이 있기 때문입니다. 다른 모듈에 대한 구성은 거의 없습니다.

예를 들어, 공통 날짜, 시간, strtotime 및 기타 기능을 제공하는 날짜 모듈이 있습니다. php.ini에서 관련 구성은 다음과 같습니다.

코드 복사 코드는 다음과 같습니다.

[날짜]
;date.timezone = '아시아/상하이'
;date.default_latitude = 31.7667
;date.default_longitude = 35.2333
;date.sunrise_zenith = 90.583333
;date.sunset_zenith = 90.583333

Zusätzlich zu diesen Modulen mit unabhängigen Konfigurationen ist die Zend-Engine auch konfigurierbar, aber die Zend-Engine verfügt nur über sehr wenige konfigurierbare Elemente, nur error_reporting, zend.enable_gc und discover_unicode.

Wie wir im vorherigen Abschnitt erwähnt haben, ruft php_module_startup php_init_config auf, dessen Zweck darin besteht, die INI-Datei zu analysieren und den Konfigurations-Hash zu generieren. Was wird als Nächstes in php_module_startup noch getan? Offensichtlich wird die Konfiguration in „configuration_hash“ auf verschiedene Module wie Zend, Core, Standard und SPL angewendet. Natürlich ist dies kein Prozess über Nacht, da PHP normalerweise viele Module enthält und diese Module auch beim PHP-Start nacheinander gestartet werden. Anschließend erfolgt die Konfiguration von Modul A während des Startvorgangs von Modul A.

Studenten mit Erfahrung in der Erweiterungsentwicklung werden direkt darauf hinweisen, dass Modul A in PHP_MINIT_FUNCTION(A) gestartet wird, nicht wahr?

Ja, wenn Modul A konfiguriert werden muss, können Sie in PHP_MINIT_FUNCTION REGISTER_INI_ENTRIES() aufrufen, um es abzuschließen. REGISTER_INI_ENTRIES durchsucht den Konfigurations-Hash nach dem vom Benutzer festgelegten Konfigurationswert basierend auf dem Namen des vom aktuellen Modul benötigten Konfigurationselements und aktualisiert ihn im eigenen globalen Bereich des Moduls.

2.1, globaler Raum des Moduls

Um zu verstehen, wie die INI-Konfiguration von „configuration_hash“ auf jedes Modul angewendet wird, ist es notwendig, zunächst den globalen Raum des PHP-Moduls zu verstehen. Für verschiedene PHP-Module können Sie einen eigenen Speicherplatz eröffnen, der für das Modul global sichtbar ist. Im Allgemeinen wird es zum Speichern der vom Modul benötigten INI-Konfiguration verwendet. Mit anderen Worten: Die Konfigurationselemente in „configuration_hash“ werden schließlich im globalen Bereich gespeichert. Während der Ausführung des Moduls müssen Sie nur direkt auf diesen globalen Bereich zugreifen, um die Benutzereinstellungen für das Modul abzurufen. Natürlich wird es auch häufig verwendet, um Zwischendaten während der Ausführung des Moduls aufzuzeichnen.

Nehmen wir als Beispiel das bcmath-Modul, das eine Schnittstelle für mathematische Berechnungen bereitstellt. Schauen wir uns zunächst die INI-Konfiguration an:

Code kopieren Der Code lautet wie folgt:

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 hat nur ein Konfigurationselement. Wir können bcmath.scale in php.ini verwenden, um das bcmath-Modul zu konfigurieren.

Schauen Sie sich als Nächstes weiterhin die globale Raumdefinition des bcmatch-Moduls an. In php_bcmath.h gibt es die folgende Anweisung:

Code kopieren Der Code lautet wie folgt:

ZEND_BEGIN_MODULE_GLOBALS(bcmath)
bc_num _zero_;
bc_num _one_;
bc_num _two_;
long bc_precision;
ZEND_END_MODULE_GLOBALS(bcmath)

Nachdem das Makro erweitert wurde, lautet es:

Code kopieren Der Code lautet wie folgt:

typedef struct _zend_bcmath_globals {
bc_num _zero_;
bc_num _one_;
bc_num _two_;
long 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 모듈은 사용자가 설정한 구성을 가져오기 위해 자체 XXX_globals에만 액세스하면 됩니다.

bcmath_globals, ini 구성 항목에 대한 한 필드 외에 다른 세 필드는 무엇입니까? 이는 모듈 전역 공간의 두 번째 역할입니다. ini 구성에 사용되는 것 외에도 모듈 실행 중에 일부 데이터를 저장할 수도 있습니다.

또 다른 예는 PHP에서 매우 일반적으로 사용되는 모듈인 json 모듈입니다.

코드 복사 코드는 다음과 같습니다.

ZEND_BEGIN_MODULE_GLOBALS(json)
int error_code;
ZEND_END_MODULE_GLOBALS(json)

json 모듈에는 ini 구성이 필요하지 않으며 전역 공간에는 error_code 필드가 하나만 있는 것을 볼 수 있습니다. 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_Globals.error_code에 접근하기 위해 JSON_G(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 구성의 종류는 각 모듈에 정의되어 있습니다. 예를 들어 코어 모듈의 경우 다음과 같은 구성 항목 정의가 있습니다.

코드 복사 코드는 다음과 같습니다.

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, 활성화_dl, php_core_globals, core_globals)
STD_PHP_INI_BOOLEAN("expose_php", "1", PHP_INI_SYSTEM, OnUpdateBool, 노출_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, 디스플레이_오류_모드 },
{ 0, PHP_INI_SYSTEM, "enable_dl", sizeof("enable_dl"), OnUpdateBool, (void *)XtOffsetOf(php_core_globals, 활성화_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, hide_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 modified; // php.ini, ini_set 등 수정 가능한 범위
char *name; char *name; // 구성 항목의 이름
단위 이름_길이;
ZEND_INI_MH((*on_modify)); // 콜백 함수, 구성 항목이 등록되거나 수정될 때 호출됩니다
void *mh_arg1; // 일반적으로 XXX_G의 구성 항목 필드 오프셋입니다
void *mh_arg2; // 일반적으로 XXX_G
void *mh_arg3; // 일반적으로 예약된 필드이며 거의 사용되지 않습니다.

문자 *값; 단위 value_length;

char *orig_value; // 구성 항목의 원래 값

단위 orig_value_length;
int orig_modifying; // 구성 항목의 원래 수정 가능
int 수정됨; // 수정되었는지 여부. 수정된 경우 orig_value는 수정 전의 값을 저장합니다.

void (*displayer)(zend_ini_entry *ini_entry, int 유형);

};

2.3, 모듈에 구성 적용 - REGISTER_INI_ENTRIES

REGISTER_INI_ENTRIES는 다양한 확장 프로그램의 PHP_MINIT_FUNCTION에서 흔히 볼 수 있습니다. REGISTER_INI_ENTRIES는 주로 모듈의 전역 공간 XXX_G를 채우고 구성_해시 값을 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 default_value;
 
// EG(ini_directives)가 등록되었습니다_zend_ini_directives
HashTable *지시문 = 등록_zend_ini_directives;
zend_bool config_directive_success = 0;
 
//ini_entry의 마지막 항목은 {0, 0, NULL, ...}으로 고정되어 있다는 점을 기억하세요
동안 (p->이름) {
​​​​ 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(모듈_번호 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(기본_값), Z_STRLEN(기본_값), hashed_ini_entry->mh_arg1, hashed_ini_entry->mh_arg2, hashed_ini_entry-> ;mh_arg3, Z END_INI_STAGE_STARTUP TSRMLS_CC) = =성공) {
                  hashed_ini_entry->값 = Z_STRVAL(기본_값);
                   hashed_ini_entry->value_length = Z_STRLEN(기본_값);
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-> , ZEND_INI_STAGE_STARTUP TSRMLS_CC);
}
        p++;
}
성공을 반환합니다.
}

간단히 말하면 위 코드의 논리는 다음과 같이 표현할 수 있습니다.

1. 모듈에서 선언한 ini 구성 항목을 EG(ini_directives)에 추가합니다. ini 구성 항목의 값은 나중에 수정될 수 있습니다.

2.configuration_hash에서 각 모듈에 필요한 ini를 찾아보세요.

찾을 수 있다면 사용자의 ini 파일에 해당 값이 설정되어 있다는 의미이며, 사용자의 설정을 사용한다는 의미입니다.
찾을 수 없다면 문제가 되지 않습니다. 모듈이 ini를 선언할 때 기본값을 가져오기 때문입니다.
3. ini 값을 XX_G에 동기화합니다. 결국, PHP를 실행하는 동안 이러한 XXX_global은 여전히 ​​역할을 합니다. 구체적인 프로세스는 각 ini 구성에 해당하는 on_modify 메소드를 호출하는 것입니다. on_modify는 ini 선언 시 모듈에 의해 지정됩니다.

실제로 함수 포인터인 on_modify를 자세히 살펴보겠습니다. 두 가지 특정 핵심 모듈의 구성 문을 살펴보겠습니다.

코드 복사 코드는 다음과 같습니다.

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에 저장된 값은 "On"이 아닌 문자열 "1"입니다
// 여기서는 atoi를 사용하여 숫자 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_length가 업데이트된다는 것입니다. 즉, 사용자가 php.ini에서 구성한 경우 EG(ini_directives)는 실제 구성된 값을 저장합니다. 사용자가 구성되지 않은 경우 EG(ini_directives)는 zend_ini_entry 선언 시 제공된 기본값을 저장합니다.

zend_register_ini_entries의 default_value 변수는 이름이 잘못되어 오해를 일으키기 쉽습니다. 실제로 default_value는 기본값을 의미하는 것이 아니라 사용자가 실제로 설정한 값을 의미합니다.

3, 요약

이제 데이터 구성_hash, EG(ini_directives) 및 PG, BG, PCRE_G, JSON_G, XXX_G...의 세 가지 부분이 모두 명확하게 설명되었습니다.

요약하자면:

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의 필드 선언에 의해 결정됩니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.