Skip to content

Commit ee9ca08

Browse files
author
Julien Pauli
committed
INI settings additions
1 parent 1c53689 commit ee9ca08

File tree

2 files changed

+117
-2
lines changed

2 files changed

+117
-2
lines changed
14.3 KB
Loading
Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,120 @@
11
Declaring and using INI settings
22
================================
33

4-
This chapter details how an extension is expected to hook into the main configuration step of PHP, by registering and
5-
making use of INI settings.
4+
This chapter details how PHP plays with its configuration and how an extension is expected to hook into the main
5+
configuration step of PHP, by registering and making use of INI settings.
6+
7+
Reminders on INI settings
8+
-------------------------
9+
10+
Before going further, you must remember how INI settings and PHP configuration work in PHP. Here are the steps, once
11+
more extracted as an interpretation of the source code. PHP INI file parsing steps happen in
12+
`php_init_config() <https://github.com/php/php-src/blob/4903f044d3a65de5b1c457d9eb618c9e247f7086/main/php_ini.c#L382>`_,
13+
and everything related to INI mainly takes place in
14+
`Zend/zend_ini.c <https://github.com/php/php-src/blob/4903f044d3a65de5b1c457d9eb618c9e247f7086/Zend/zend_ini.c>`_.
15+
16+
First, PHP tries to parse one or several INI files. Those files may declare some settings, that may or may not be
17+
relevant in the future. At this very early stage (INI files parsing), PHP knows nothing about what to expect in such
18+
files. It just parses the content, and saves this one for later use.
19+
20+
Then as a second step, PHP boots up its extensions, calling their ``MINIT()``. If you need to remember about the PHP
21+
lifecycle, :doc:`read the dedicated chapter <php_lifecycle>`. ``MINIT()`` may now register the current
22+
extension INI settings of interest. When registering the setting, the engine checks if it parsed its definition before,
23+
as part of the INI files parsing step. If that was the case, then the INI setting is registered into the engine and it
24+
gets the value that was parsed from INI files. If it had no definition in INI files parsed, then it gets registered with
25+
the default value the extension designer gives to the API.
26+
27+
.. note:: The default value the setting will get is probed from INI files parsing. If none is found, then the default
28+
is the one given by the extension developer, not the other way around.
29+
30+
The default value we are talking about here is called the **"master value"**. You may recall it from a ``phpinfo()``
31+
output, right ?:
32+
33+
.. image:: ./images/php_extensions_ini.png
34+
:align: center
35+
36+
The master value cannot change. If during a request, the user wants to change the configuration, f.e using
37+
``ini_set()``, and if he's allowed to, then the changed value will be the **"local value"** , that is the current value
38+
for the current request. The engine will automaticaly restore the local value to the master value value at the end of
39+
the request.
40+
41+
``ini_get()`` reads the current request-bound local value, whereas ``get_cfg_var()`` will read the master value
42+
whatever happens.
43+
44+
.. note:: If you have understood correctly, ``get_cfg_var()`` will return false for any value asked that was not part of
45+
INI file parsing, even if the value exists and was declared by an extension.
46+
And the opposite is true: ``ini_get()`` will return false if asked for a setting that no extension has declared
47+
interest in, even if such a setting was part of an INI file parsing (like php.ini).
48+
49+
Zoom on INI settings
50+
--------------------
51+
52+
Into the engine, an INI setting is represented by a ``zend_ini_entry`` structure::
53+
54+
struct _zend_ini_entry {
55+
zend_string *name;
56+
int (*on_modify)(zend_ini_entry *entry, zend_string *new_value, void *mh_arg1, void *mh_arg2, void *mh_arg3,
57+
int stage);
58+
void *mh_arg1;
59+
void *mh_arg2;
60+
void *mh_arg3;
61+
zend_string *value;
62+
zend_string *orig_value;
63+
void (*displayer)(zend_ini_entry *ini_entry, int type);
64+
int modifiable;
65+
66+
int orig_modifiable;
67+
int modified;
68+
int module_number;
69+
};
70+
71+
Nothing really strong in such a structure. Setting's ``name`` and ``value`` are the most commonly used fields. Note
72+
however that the value is a string (as :doc:`zend_string <../internal_types/strings/zend_strings>`) and nothing else.
73+
Then, like we detailed in the introduction chapter above, we find the ``orig_value``, ``orig_modified``, ``modifiable``
74+
and ``modified`` fields which are related to the modification of the setting's value. The setting must keep in memory
75+
its original value (as "master value"). ``modifiable`` tells if the setting is actually modifable, and must have one of
76+
the values you should be aware of from PHP userland : ``ZEND_INI_USER``, ``ZEND_INI_PERDIR``, ``ZEND_INI_SYSTEM`` or
77+
``ZEND_INI_ALL``.
78+
79+
Then come two handlers: ``on_modify()`` is called whenever the current setting's value is modified, like f.e using a call
80+
to ``ini_set()`` (but not only). We'll focus deeper on ``on_modify()`` later, but think of it as being a
81+
*validator function* (f.e if the setting is expected to represent an integer, you may validate the values you'll be
82+
given against integers). It also serve as a memory bridge to update global values, we'll get back on that later as well.
83+
84+
``diplayer()`` is less useful, and you usually don't pass any. ``displayer()`` is about how to display your setting.
85+
F.e, you may remember that PHP tend to display *On* for boolean values of *true*/*yes*/*on*/*1* etc. That's the
86+
``displayer()`` job.
87+
88+
You will also need to deal with this structure ``zend_ini_entry_def``::
89+
90+
typedef struct _zend_ini_entry_def {
91+
const char *name;
92+
ZEND_INI_MH((*on_modify));
93+
void *mh_arg1;
94+
void *mh_arg2;
95+
void *mh_arg3;
96+
const char *value;
97+
void (*displayer)(zend_ini_entry *ini_entry, int type);
98+
int modifiable;
99+
100+
uint name_length;
101+
uint value_length;
102+
} zend_ini_entry_def;
103+
104+
Pretty much similar to ``zend_ini_entry``, ``zend_ini_entry_def`` is used by the programmer (you) when he must register
105+
an INI setting against the engine. The engine reads a ``zend_ini_entry_def``, and creates internally a
106+
``zend_ini_entry`` for its own usage, based on the definition model you provide. Easy.
107+
108+
Registering INI entries
109+
-----------------------
110+
111+
INI settings are persistent through requests. They can change their value during a request (runtime), but they'll go back
112+
to original value at request shutdown. Thus, registering INI settings is done once for all, in ``MINIT()`` hook of your
113+
extension.
114+
115+
What you must do is declare a vector of ``zend_ini_entry_def``, you'll be helped with dedicated macros for that. Then,
116+
you register your vector against the engine and you are done for the declaration. Let's see that::
117+
118+
119+
120+

0 commit comments

Comments
 (0)