ホームページ > バックエンド開発 > PHPチュートリアル > php の ini 設定を深く理解する (1)、ini_PHP チュートリアルを深く理解する

php の ini 設定を深く理解する (1)、ini_PHP チュートリアルを深く理解する

WBOY
リリース: 2016-07-13 10:17:25
オリジナル
997 人が閲覧しました

phpのini設定を深く理解する(1)、iniを深く理解する

この記事では、特定の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 ファイルの解析に関連する実装は次のとおりです:

リーリー

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 行を記述します。

リーリー

その後、最終的に生成された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 ファイルを解析することです。

第四,在configuration_hash中,key是字符串,那么值的类型是什么?答案也是字符串(除了上述很特殊的数组)。具体来说,比如下面的配置:

display_errors =<span> On
log_errors </span>=<span> Off
log_errors_max_len </span>= 1024
ログイン後にコピー

那么最后configuration_hash中实际存放的键值对为:

key: "display_errors"<span>
val : </span>"1"<span>

key: </span>"log_errors"<span>
val : </span>""<span>

key: </span>"log_errors_max_len"<span>
val : </span>"1024"
ログイン後にコピー

注意log_errors,其存放的值连"0"都不是,就是一个实实在在地空字符串。另外,log_errors_max_len也并非数字,而是字符串1024。

分析至此,基本上解析ini文件相关的内容都说清楚了。简单总结一下:

1,解析ini发生在php_module_startup阶段

2,解析结果存放在configuration_hash里。

2,配置作用到模块

php的大致结构可以看成是最下层有一个zend引擎,它负责与OS进行交互、编译php代码、提供内存托管等等,在zend引擎的上层,排列着很多很多的模块。其中最核心的就一个Core模块,其他还有比如Standard,PCRE,Date,Session等等...这些模块还有另一个名字叫php扩展。我们可以简单理解为,每个模块都会提供一组功能接口给开发者来调用,举例来说,常用的诸如explode,trim,array等内置函数,便是由Standard模块提供的。

为什么需要谈到这些,是因为在php.ini里除了针对php自身,也就是针对Core模块的一些配置(例如safe_mode,display_errors,max_execution_time等),还有相当多的配置是针对其他不同模块的。

例如,date模块,它提供了常见的date, time,strtotime等函数。在php.ini中,它的相关配置形如:

<span>[</span><span>Date</span><span>]</span><span>
;</span><span>date.timezone = 'Asia/Shanghai'</span><span>
;</span><span>date.default_latitude = 31.7667</span><span>
;</span><span>date.default_longitude = 35.2333<br />;date.sunrise_zenith = 90.583333<br />;date.sunset_zenith = 90.583333<br /></span>
ログイン後にコピー

除了这些模块拥有独立的配置,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,模块的全局空间

要理解如何将ini配置从configuration_hash作用到各个模块之前,有必要先了解一下php模块的全局空间。对于不同的php模块,均可以开辟一块属于自己的存储空间,并且这块空间对于该模块来说,是全局可见的。一般而言,它会被用来存放该模块所需的ini配置。也就是说,configuration_hash中的配置项,最终会被存放到该全局空间中。在模块的执行过程中,只需要直接访问这块全局空间,就可以拿到用户针对该模块进行的设置。当然,它也经常被用来记录模块在执行过程中的中间数据。

我们以bcmath模块来举例说明,bcmath是一个提供数学计算方面接口的php模块,首先我们来看看它有哪些ini配置:

<span>PHP_INI_BEGIN()
    STD_PHP_INI_ENTRY(</span><span>"</span><span>bcmath.scale</span><span>"</span>, <span>"</span><span>0</span><span>"</span><span>, PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
PHP_INI_END()</span>
ログイン後にコピー

bcmath只有一个配置项,我们可以在php.ini中用bcmath.scale来配置bcmath模块。

接下来继续看看bcmatch模块的全局空间定义。在php_bcmath.h中有如下声明:

<span>ZEND_BEGIN_MODULE_GLOBALS(bcmath)<br />    bc_num _zero_;<br />    bc_num _one_;<br />    bc_num _two_;<br />    long bc_precision;<br />ZEND_END_MODULE_GLOBALS(bcmath)</span>
ログイン後にコピー

宏展开之后,即为:

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;<br />ZEND_DECLARE_MODULE_GLOBALS(bcmath) 
ログイン後にコピー

可以看出,用ZEND_DECLARE_MODULE_GLOBALS完成了对变量bcmath_globals的定义。

bcmath_globals是一块真正的全局空间,它包含有四个字段。其最后一个字段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配置项,其他还有三个字段为何意?这就是模块全局空间的第二个作用,它除了用于ini配置,还可以存储模块执行过程中的一些数据。

再例如json模块,也是php中一个很常用的模块:

<span>ZEND_BEGIN_MODULE_GLOBALS(json)
    </span><span>int</span><span> error_code;
ZEND_END_MODULE_GLOBALS(json)</span>
ログイン後にコピー

可以看到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宏:

<span>#define</span> 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模块的全局变量。

<span>#define</span> PG(v) (core_globals.v)
<span>#define</span> BG(v) (basic_globals.v)
ログイン後にコピー

2.2,如何确定一个模块需要哪些配置呢?

模块需要什么样的INI配置,都是在各个模块中自己定义的。举例来说,对于Core模块,有如下的配置项定义:

<span>PHP_INI_BEGIN()
    ......
    STD_PHP_INI_ENTRY_EX(</span>"display_errors", "1", PHP_INI_ALL,    OnUpdateDisplayErrors, display_errors, php_core_globals, core_globals,<span> display_errors_mode)
    STD_PHP_INI_BOOLEAN(</span>"enable_dl",       "1", PHP_INI_SYSTEM, OnUpdateBool,          enable_dl,      php_core_globals,<span> core_globals)
    STD_PHP_INI_BOOLEAN(</span>"expose_php",      "1", PHP_INI_SYSTEM, OnUpdateBool,          expose_php,     php_core_globals,<span> core_globals)
    STD_PHP_INI_BOOLEAN(</span>"safe_mode",       "0", PHP_INI_SYSTEM, OnUpdateBool,          safe_mode,      php_core_globals,<span> core_globals)
    ......
PHP_INI_END()</span>
ログイン後にコピー

可以在php-src\main\main.c文件大概450+行找到上述代码。其中涉及的宏比较多,有ZEND_INI_BEGIN 、ZEND_INI_END、PHP_INI_ENTRY_EX、STD_PHP_INI_BOOLEAN等等,本文不一一赘述,感兴趣的读者可自行分析。

上述代码进行宏展开后得到:

<span>static</span> <span>const</span> zend_ini_entry ini_entries[] =<span> {
    ..
    { </span><span>0</span>, PHP_INI_ALL,    <span>"</span><span>display_errors</span><span>"</span>,<span>sizeof</span>(<span>"</span><span>display_errors</span><span>"</span>),OnUpdateDisplayErrors,(<span>void</span> *)XtOffsetOf(php_core_globals, display_errors), (<span>void</span> *)&core_globals, NULL, <span>"</span><span>1</span><span>"</span>, <span>sizeof</span>(<span>"</span><span>1</span><span>"</span>)-<span>1</span>, NULL, <span>0</span>, <span>0</span>, <span>0</span><span>, display_errors_mode },
    { </span><span>0</span>, PHP_INI_SYSTEM, <span>"</span><span>enable_dl</span><span>"</span>,     <span>sizeof</span>(<span>"</span><span>enable_dl</span><span>"</span>),     OnUpdateBool,         (<span>void</span> *)XtOffsetOf(php_core_globals, enable_dl),      (<span>void</span> *)&core_globals, NULL, <span>"</span><span>1</span><span>"</span>, <span>sizeof</span>(<span>"</span><span>1</span><span>"</span>)-<span>1</span>, NULL, <span>0</span>, <span>0</span>, <span>0</span><span>, zend_ini_boolean_displayer_cb },
    { </span><span>0</span>, PHP_INI_SYSTEM, <span>"</span><span>expose_php</span><span>"</span>,    <span>sizeof</span>(<span>"</span><span>expose_php</span><span>"</span>),    OnUpdateBool,         (<span>void</span> *)XtOffsetOf(php_core_globals, expose_php),     (<span>void</span> *)&core_globals, NULL, <span>"</span><span>1</span><span>"</span>, <span>sizeof</span>(<span>"</span><span>1</span><span>"</span>)-<span>1</span>, NULL, <span>0</span>, <span>0</span>, <span>0</span><span>, zend_ini_boolean_displayer_cb },
    { </span><span>0</span>, PHP_INI_SYSTEM, <span>"</span><span>safe_mode</span><span>"</span>,     <span>sizeof</span>(<span>"</span><span>safe_mode</span><span>"</span>),     OnUpdateBool,         (<span>void</span> *)XtOffsetOf(php_core_globals, safe_mode),      (<span>void</span> *)&core_globals, NULL, <span>"</span><span>0</span><span>"</span>, <span>sizeof</span>(<span>"</span><span>0</span><span>"</span>)-<span>1</span>, NULL, <span>0</span>, <span>0</span>, <span>0</span><span>, zend_ini_boolean_displayer_cb },
    ...
    { </span><span>0</span>, <span>0</span>, NULL, <span>0</span>, NULL, NULL, NULL, NULL, NULL, <span>0</span>, NULL, <span>0</span>, <span>0</span>, <span>0</span><span>, NULL }
};</span>
ログイン後にコピー

我们看到,配置项的定义,其本质上就是定义了一个zend_ini_entry类型的数组。zend_ini_entry结构体的字段具体含义为:

<span>struct</span><span> _zend_ini_entry {
    </span><span>int</span> module_number;                <span>//</span><span> 模块的id</span>
    <span>int</span> modifiable;                   <span>//</span><span> 可被修改的范围,例如php.ini,ini_set</span>
    <span>char</span> *name;                       <span>//</span><span> 配置项的名称</span>
    <span>uint</span><span> name_length;
    ZEND_INI_MH((</span>*on_modify));        <span>//</span><span> 回调函数,配置项注册或修改的时候会调用</span>
    <span>void</span> *mh_arg1;                    <span>//</span><span> 通常为配置项字段在XXX_G中的偏移量</span>
    <span>void</span> *mh_arg2;                    <span>//</span><span> 通常为XXX_G</span>
    <span>void</span> *mh_arg3;                    <span>//</span><span> 通常为保留字段,极少用到</span>

    <span>char</span> *value;                      <span>//</span><span> 配置项的值</span>
    <span>uint</span><span> value_length;

    </span><span>char</span> *orig_value;                 <span>//</span><span> 配置项的原始值</span>
    <span>uint</span><span> orig_value_length;
    </span><span>int</span> orig_modifiable;              <span>//</span><span> 配置项的原始modifiable</span>
    <span>int</span> modified;                     <span>//</span><span> 是否发生过修改,如果有修改,则orig_value会保存修改前的值</span>

    <span>void</span> (*displayer)(zend_ini_entry *ini_entry, <span>int</span><span> type);
};</span>
ログイン後にコピー

2.3,将配置作用到模块——REGISTER_INI_ENTRIES

经常能够在不同扩展的PHP_MINIT_FUNCTION里看到REGISTER_INI_ENTRIES。REGISTER_INI_ENTRIES主要负责完成两件事情,第一,对模块的全局空间XXX_G进行填充,同步configuration_hash中的值到XXX_G中去。其次,它还生成了EG(ini_directives)。

REGISTER_INI_ENTRIES也是一个宏,展开之后实则为zend_register_ini_entries方法。具体来看下zend_register_ini_entries的实现:

ZEND_API <span>int</span> zend_register_ini_entries(<span>const</span> zend_ini_entry *ini_entry, <span>int</span> module_number TSRMLS_DC) <span>/*</span><span> {{{ </span><span>*/</span><span>
{
    </span><span>//</span><span> ini_entry为zend_ini_entry类型数组,p为数组中每一项的指针</span>
    <span>const</span> zend_ini_entry *p =<span> ini_entry;
    zend_ini_entry </span>*<span>hashed_ini_entry;
    zval default_value;
    
    </span><span>//</span><span> EG(ini_directives)就是registered_zend_ini_directives</span>
    HashTable *directives =<span> registered_zend_ini_directives;
    zend_bool config_directive_success </span>= <span>0</span><span>;
    
    </span><span>//</span><span> 还记得ini_entry最后一项固定为{ 0, 0, NULL, ... }么</span>
    <span>while</span> (p-><span>name) {
        config_directive_success </span>= <span>0</span><span>;
        
        </span><span>//</span><span> 将p指向的zend_ini_entry加入EG(ini_directives)</span>
        <span>if</span> (zend_hash_add(directives, p->name, p->name_length, (<span>void</span>*)p, <span>sizeof</span>(zend_ini_entry), (<span>void</span> **) &hashed_ini_entry) ==<span> FAILURE) {
            zend_unregister_ini_entries(module_number TSRMLS_CC);
            </span><span>return</span><span> FAILURE;
        }
        hashed_ini_entry</span>->module_number =<span> module_number;
        
        </span><span>//</span><span> 根据name去configuration_hash中查询,取出来的结果放在default_value中
        </span><span>//</span><span> 注意default_value的值比较原始,一般是数字、字符串、数组等,具体取决于php.ini中的写法</span>
        <span>if</span> ((zend_get_configuration_directive(p->name, p->name_length, &default_value)) ==<span> SUCCESS) {
            </span><span>//</span><span> 调用on_modify更新到模块的全局空间XXX_G中</span>
            <span>if</span> (!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_arg2, hashed_ini_entry->mh_arg3, ZEND_INI_STAGE_STARTUP TSRMLS_CC) ==<span> SUCCESS) {
                hashed_ini_entry</span>->value =<span> Z_STRVAL(default_value);
                hashed_ini_entry</span>->value_length =<span> Z_STRLEN(default_value);
                config_directive_success </span>= <span>1</span><span>;
            }
        }

        </span><span>//</span><span> 如果configuration_hash中没有找到,则采用默认值</span>
        <span>if</span> (!config_directive_success && hashed_ini_entry-><span>on_modify) {
            hashed_ini_entry</span>->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-><span>mh_arg3, ZEND_INI_STAGE_STARTUP TSRMLS_CC);
        }
        p</span>++<span>;
    }
    </span><span>return</span><span> SUCCESS;
}</span>
ログイン後にコピー

简单来说,可以把上述代码的逻辑表述为:

1,将模块声明的ini配置项添加到EG(ini_directives)中。注意,ini配置项的值可能在随后被修改。

2,尝试去configuration_hash中寻找各个模块需要的ini。

  • 如果能够找到,说明用户叜ini文件中配置了该值,那么采用用户的配置。
  • 如果没有找到,OK,没有关系,因为模块在声明ini的时候,会带上默认值。

3,将ini的值同步到XX_G里面。毕竟在php的执行过程中,起作用的还是这些XXX_globals。具体的过程是调用每条ini配置对应的on_modify方法完成,on_modify由模块在声明ini的时候进行指定。

我们来具体看下on_modify,它其实是一个函数指针,来看两个具体的Core模块的配置声明:

STD_PHP_INI_BOOLEAN(<span>"</span><span>log_errors</span><span>",</span>      <span>"</span><span>0</span><span>"</span><span>,    PHP_INI_ALL, OnUpdateBool, log_errors,         php_core_globals, core_globals)
STD_PHP_INI_ENTRY(</span><span>"</span><span>log_errors_max_len</span><span>"</span>,<span>"</span><span>1024</span><span>"</span>, 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 =<span> On
log_errors_max_len </span>= 1024
ログイン後にコピー

具体来看下OnUpdateBool函数:

<span>ZEND_API ZEND_INI_MH(OnUpdateBool) 
{
    zend_bool </span>*<span>p;
    
    </span><span>//</span><span> base表示core_globals的地址</span>
    <span>char</span> *<span>base</span> = (<span>char</span> *<span>) mh_arg2;

    </span><span>//</span><span> p表示core_globals的地址加上log_errors字段的偏移量
    </span><span>//</span><span> 得到的即为log_errors字段的地址</span>
    p = (zend_bool *) (<span>base</span>+<span>(size_t) mh_arg1);  

    </span><span>if</span> (new_value_length == <span>2</span> && strcasecmp(<span>"</span><span>on</span><span>"</span>, new_value) == <span>0</span><span>) {
        </span>*p = (zend_bool) <span>1</span><span>;
    }
    </span><span>else</span> <span>if</span> (new_value_length == <span>3</span> && strcasecmp(<span>"</span><span>yes</span><span>"</span>, new_value) == <span>0</span><span>) {
        </span>*p = (zend_bool) <span>1</span><span>;
    }
    </span><span>else</span> <span>if</span> (new_value_length == <span>4</span> && strcasecmp(<span>"</span><span>true</span><span>"</span>, new_value) == <span>0</span><span>) {
        </span>*p = (zend_bool) <span>1</span><span>;
    }
    </span><span>else</span><span> {
        </span><span>//</span><span> configuration_hash中存放的value是字符串"1",而非"On"
        </span><span>//</span><span> 因此这里用atoi转化成数字1</span>
        *p =<span> (zend_bool) atoi(new_value);
    }
    </span><span>return</span><span> SUCCESS;
}</span>
ログイン後にコピー

最令人费解的估计就是mh_arg1和mh_arg2了,其实对照前面所述的zend_ini_entry定义,mh_arg1,mh_arg2还是很容易参透的。mh_arg1表示字节偏移量,mh_arg2表示XXX_globals的地址。因此,(char *)mh_arg2 + mh_arg1的结果即为XXX_globals中某个字段的地址。具体到本case中,就是计算core_globals中log_errors的地址。因此,当OnUpdateBool最后执行到

*p = (zend_bool) atoi(new_value);

其作用就相当于

core_globals.log_errors = (zend_bool) atoi("1");

分析完了OnUpdateBool,我们再来看OnUpdateLong便觉得一目了然:

<span>ZEND_API ZEND_INI_MH(OnUpdateLong)
{
    </span><span>long</span> *<span>p;
    </span><span>char</span> *<span>base</span> = (<span>char</span> *<span>) mh_arg2;

    </span><span>//</span><span> 获得log_errors_max_len的地址</span>
    p = (<span>long</span> *) (<span>base</span>+<span>(size_t) mh_arg1);

    </span><span>//</span><span> 将"1024"转化成long型,并赋值给core_globals.log_errors_max_len</span>
    *p =<span> zend_atol(new_value, new_value_length);
    </span><span>return</span><span> SUCCESS;
}</span>
ログイン後にコピー

最后需要注意的是,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...已经都交代清楚了。

总结一下:

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中的字段声明来决定。

 

php中ini的配置是怎做的

直接编辑php目录下的php.ini文件即可

有一个“register_globals = Off”值,这个值是用来打开全局变量的,比如表单送过来的值,如果这个值设为“Off”,就只能用“$_POST['变量名']、$_GET['变量名 ']”等来取得送过来的值,如果设为“On”,就可以直接使用“$变量名”来获取送过来的值,当然,设为“Off”就比较安全,不会让人轻易将网页间传送 的数据截取。这个值是否改成“On”就看自己感觉了,是安全重要还是方便重要?
要用mysql,就要把“;extension= php_mysql.dll”前的“;”去掉。所有的模块文件都放在php解压缩目录的“ext”之下,用什么就把前面的“;”去掉就行了。
 

php读取ini配置文件属性

ini的内容格式如下,请根据自己的INI,格式修改下段程序.
autostart = false
font_size = 12
font_color = red
===================
function get_ini_file($file_name = "demo.ini"){
$str=file_get_contents($file_name);//读取ini文件存到一个字符串中.
$ini_list = explode("\r\n",$str);//按换行拆开,放到数组中.
$ini_items = array();
foreach($ini_list as $item){
$one_item = explode("=",$item);
if(isset($one_item[0])&&isset($one_item[1])) $ini_items[trim($one_item[0])] = trim($one_item[1]); //存成key=>value的形式.
}
return $ini_items;
}

function get_ini_item($ini_items = null,$item_name = ''){//获得INI条目的值.
if(empty($ini_items)) return "";
else return $ini_items[$item_name];
}

$ini_items = get_ini_file("demo.ini");

echo get_ini_item($ini_items,'font_size'); //输出获得的值.
 

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/892527.htmlTechArticle深入理解php中的ini配置(1),深入理解ini 这篇文章不会详细叙述某个ini配置项的用途,这些在手册上已经讲解的面面俱到。我只是想从某个特...
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート