Skip to content

Commit 72a0694

Browse files
committed
Create book for docs
1 parent 10957e4 commit 72a0694

21 files changed

+1057
-0
lines changed

.github/workflows/docs.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Docs
2+
on:
3+
push:
4+
branches:
5+
- master
6+
paths:
7+
- docs/*
8+
pull_request:
9+
paths:
10+
- docs/*
11+
jobs:
12+
pages:
13+
runs-on: ubuntu-22.04
14+
permissions:
15+
pages: write
16+
id-token: write
17+
steps:
18+
- name: git checkout
19+
uses: actions/checkout@v4
20+
- name: Install dependencies
21+
run: pip install sphinx-design sphinxawesome-theme rstfmt
22+
- name: Check formatting
23+
run: rstfmt --check -w 100 docs/source
24+
- name: Publish
25+
if: github.event_name == 'push'
26+
uses: sphinx-notes/pages@v3
27+
with:
28+
checkout: false
29+
documentation_path: docs/source
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

docs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build/

docs/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# php-src docs
2+
3+
This is the home of the php-src internal documentation. It is in very early stages, but is intended
4+
to become the primary place where new information about php-src is documented. Over time, it is
5+
expected to replace various mediums like:
6+
7+
* https://www.phpinternalsbook.com/
8+
* https://wiki.php.net/internals
9+
* Blogs from contributors
10+
11+
## How to build
12+
13+
`python` 3 and `pip` are required.
14+
15+
```bash
16+
pip install sphinx sphinx-design sphinxawesome-theme
17+
make html
18+
```
19+
20+
That's it! You can view the documentation under `./build/html/index.html` in your browser.

docs/make.bat

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
@ECHO OFF
2+
3+
pushd %~dp0
4+
5+
REM Command file for Sphinx documentation
6+
7+
if "%SPHINXBUILD%" == "" (
8+
set SPHINXBUILD=sphinx-build
9+
)
10+
set SOURCEDIR=source
11+
set BUILDDIR=build
12+
13+
%SPHINXBUILD% >NUL 2>NUL
14+
if errorlevel 9009 (
15+
echo.
16+
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
17+
echo.installed, then set the SPHINXBUILD environment variable to point
18+
echo.to the full path of the 'sphinx-build' executable. Alternatively you
19+
echo.may add the Sphinx directory to PATH.
20+
echo.
21+
echo.If you don't have Sphinx installed, grab it from
22+
echo.https://www.sphinx-doc.org/
23+
exit /b 1
24+
)
25+
26+
if "%1" == "" goto help
27+
28+
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29+
goto end
30+
31+
:help
32+
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33+
34+
:end
35+
popd

docs/source/_static/.gitkeep

Whitespace-only changes.

docs/source/_templates/.gitkeep

Whitespace-only changes.

docs/source/conf.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Configuration file for the Sphinx documentation builder.
2+
#
3+
# For the full list of built-in configuration values, see the documentation:
4+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
5+
6+
from dataclasses import asdict
7+
from sphinxawesome_theme import ThemeOptions
8+
from sphinxawesome_theme.postprocess import Icons
9+
from sphinx.highlighting import lexers
10+
from pygments.lexers.web import PhpLexer
11+
12+
lexers['php'] = PhpLexer(startinline=True)
13+
lexers['php-annotations'] = PhpLexer(startinline=True)
14+
15+
project = 'php-src docs'
16+
author = 'The PHP Group'
17+
extensions = [
18+
'sphinx_design',
19+
'sphinxawesome_theme.highlighting',
20+
]
21+
templates_path = ['_templates']
22+
html_theme = 'sphinxawesome_theme'
23+
html_static_path = ['_static']
24+
html_title = project
25+
html_permalinks_icon = Icons.permalinks_icon
26+
theme_options = ThemeOptions(
27+
show_prev_next=True,
28+
extra_header_link_icons={
29+
'repository on GitHub': {
30+
'link': 'https://github.com/php/php-src',
31+
'icon': (
32+
'<svg height="26px" style="margin-top:-2px;display:inline" '
33+
'viewBox="0 0 45 44" '
34+
'fill="currentColor" xmlns="http://www.w3.org/2000/svg">'
35+
'<path fill-rule="evenodd" clip-rule="evenodd" '
36+
'd="M22.477.927C10.485.927.76 10.65.76 22.647c0 9.596 6.223 17.736 '
37+
'14.853 20.608 1.087.2 1.483-.47 1.483-1.047 '
38+
'0-.516-.019-1.881-.03-3.693-6.04 '
39+
'1.312-7.315-2.912-7.315-2.912-.988-2.51-2.412-3.178-2.412-3.178-1.972-1.346.149-1.32.149-1.32 ' # noqa
40+
'2.18.154 3.327 2.24 3.327 2.24 1.937 3.318 5.084 2.36 6.321 '
41+
'1.803.197-1.403.759-2.36 '
42+
'1.379-2.903-4.823-.548-9.894-2.412-9.894-10.734 '
43+
'0-2.37.847-4.31 2.236-5.828-.224-.55-.969-2.759.214-5.748 0 0 '
44+
'1.822-.584 5.972 2.226 '
45+
'1.732-.482 3.59-.722 5.437-.732 1.845.01 3.703.25 5.437.732 '
46+
'4.147-2.81 5.967-2.226 '
47+
'5.967-2.226 1.185 2.99.44 5.198.217 5.748 1.392 1.517 2.232 3.457 '
48+
'2.232 5.828 0 '
49+
'8.344-5.078 10.18-9.916 10.717.779.67 1.474 1.996 1.474 4.021 0 '
50+
'2.904-.027 5.247-.027 '
51+
'5.96 0 .58.392 1.256 1.493 1.044C37.981 40.375 44.2 32.24 44.2 '
52+
'22.647c0-11.996-9.726-21.72-21.722-21.72" '
53+
'fill="currentColor"/></svg>'
54+
),
55+
},
56+
},
57+
)
58+
html_theme_options = asdict(theme_options)
59+
pygments_style = 'sphinx'
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#################
2+
Data structures
3+
#################
4+
5+
.. toctree::
6+
:hidden:
7+
8+
zval
9+
reference-counting
10+
zend_string
11+
12+
This section provides an overview of the core data structures used in php-src.
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
####################
2+
Reference counting
3+
####################
4+
5+
In languages like C, when you need memory for storing data for an indefinite period of time or in a
6+
large amount, you call ``malloc`` and ``free`` to acquire and release blocks of memory of some size.
7+
This sounds simple on the surface but turns out to be quite tricky, mainly because the data may not
8+
be freed for as long as it is used anywhere in the program. Sometimes this makes it unclear who is
9+
responsible for freeing the memory, and when to do so. Failure to handle this correctly may result
10+
in a use-after-free, double-free, or memory leak.
11+
12+
In PHP you usually do not need to think about memory management. The engine takes care of allocating
13+
and freeing memory for you by tracking which values are no longer needed. It does this by assigning
14+
a reference count to each allocated value, often abbreviated as refcount or RC. Whenever a reference
15+
to a value is passed somewhere else, its reference count is increased to indicate the value is now
16+
used by another party. When the party no longer needs the value, it is responsible for decreasing
17+
the reference count. Once the reference count reaches zero, we know the value is no longer needed
18+
anywhere, and that it may be freed.
19+
20+
.. code:: php
21+
22+
$a = new stdClass; // RC 1
23+
$b = $a; // RC 2
24+
unset($a); // RC 1
25+
unset($b); // RC 0, free
26+
27+
Reference counting is needed for types that store auxiliary data, which are the following:
28+
29+
- Strings
30+
- Arrays
31+
- Objects
32+
- References
33+
- Resources
34+
35+
These are either reference types (objects, references and resources) or they are large types that
36+
don't fit in a single ``zend_value`` directly (strings, arrays). Simpler types either don't store a
37+
value at all (``null``, ``false``, ``true``) or their value is small enough to fit directly in
38+
``zend_value`` (``int``, ``float``).
39+
40+
All of the reference counted types share a common initial struct sequence.
41+
42+
.. code:: c
43+
44+
typedef struct _zend_refcounted_h {
45+
uint32_t refcount; /* reference counter 32-bit */
46+
union {
47+
uint32_t type_info;
48+
} u;
49+
} zend_refcounted_h;
50+
51+
struct _zend_string {
52+
zend_refcounted_h gc;
53+
// ...
54+
};
55+
56+
struct _zend_array {
57+
zend_refcounted_h gc;
58+
// ...
59+
};
60+
61+
The ``zend_refcounted_h`` struct is simple. It contains the reference count, and a ``type_info``
62+
field that repeats some of the type information that is also stored in the ``zval``, for situations
63+
where we're not dealing with a ``zval`` directly. It also stores some additional fields, described
64+
under `GC flags`_.
65+
66+
********
67+
Macros
68+
********
69+
70+
As with ``zval``, ``zend_refcounted_h`` members should not be accessed directly. Instead, you should
71+
use the provided macros. There are macros that work with reference counted types directly, prefixed
72+
with ``GC_``, or macros that work on ``zval`` values, usually prefixed with ``Z_``. Unfortunately,
73+
naming is not always consistent.
74+
75+
.. list-table:: ``zval`` macros
76+
:header-rows: 1
77+
78+
- - Macro
79+
- Non-RC [#non-rc]_
80+
- Description
81+
82+
- - ``Z_REFCOUNT[_P]``
83+
- No
84+
- Returns the reference count.
85+
86+
- - ``Z_ADDREF[_P]``
87+
- No
88+
- Increases the reference count.
89+
90+
- - ``Z_TRY_ADDREF[_P]``
91+
- Yes
92+
- Increases the reference count. May be called on any ``zval``.
93+
94+
- - ``zval_ptr_dtor``
95+
- Yes
96+
- Decreases the reference count and frees the value if the reference count reaches zero.
97+
98+
.. [#non-rc]
99+
100+
Whether the macro works with non-reference counted types. If it does, the operation is usually a
101+
no-op. If it does not, using the macro on these values is undefined behavior.
102+
103+
.. list-table:: ``zend_refcounted_h`` macros
104+
:header-rows: 1
105+
106+
- - Macro
107+
- Immutable [#immutable]_
108+
- Description
109+
110+
- - ``GC_REFCOUNT[_P]``
111+
- Yes
112+
- Returns the reference count.
113+
114+
- - ``GC_ADDREF[_P]``
115+
- No
116+
- Increases the reference count.
117+
118+
- - ``GC_TRY_ADDREF[_P]``
119+
- Yes
120+
- Increases the reference count.
121+
122+
- - ``GC_DTOR[_P]``
123+
- Yes
124+
- Decreases the reference count and frees the value if the reference count reaches zero.
125+
126+
.. [#immutable]
127+
128+
Whether the macro works with immutable types, described under `Immutable reference counted types`_.
129+
130+
************
131+
Separation
132+
************
133+
134+
PHP has value and reference types. Reference types are types that are shared through a reference, a
135+
"pointer" to the value, rather than the value itself. Modifying such a value in one place changes it
136+
for all of its observers. For example, writing to a property changes the property in every place the
137+
object is referenced. Value types, on the other hand, are copied when passed to another party.
138+
Modifying the original value does not affect the copy, and vice versa.
139+
140+
In PHP, arrays and strings are value types. Since they are also reference counted types, this
141+
requires some special care when modifying values. In particular, we need to make sure that modifying
142+
the value is not observable from other places. Modifying a value with RC 1 is unproblematic, since
143+
we are the values sole owner. However, if the value has a reference count of >1, we need to create a
144+
fresh copy before modifying it. This process is called separation or CoW (copy on write).
145+
146+
.. code:: php
147+
148+
$a = [1, 2, 3]; // RC 1
149+
$b = $a; // RC 2
150+
$b[] = 4; // Separation, $a RC 1, $b RC 1
151+
var_dump($a); // [1, 2, 3]
152+
var_dump($b); // [1, 2, 3, 4]
153+
154+
***********************************
155+
Immutable reference counted types
156+
***********************************
157+
158+
Sometimes, even a reference counted type is not reference counted. When PHP runs in a multi-process
159+
or multi-threaded environment with opcache enabled, it shares some common values between processes
160+
or threads to reduce memory consumption. As you may know, sharing memory between processes or
161+
threads can be tricky and requires special care when modifying values. In particular, modification
162+
usually requires exclusive access to the memory so that the other processes or threads wait until
163+
the value is done being updated. In this case, this synchronization is avoided by making the value
164+
immutable and never modifying the reference count. Such values will receive the ``GC_IMMUTABLE``
165+
flag in their ``gc->u.type_info`` field.
166+
167+
Some macros like ``GC_TRY_ADDREF`` will guard against immutable values. You should not use immutable
168+
values on some macros, like ``GC_ADDREF``. This will result in undefined behavior, because the macro
169+
will not check whether the value is immutable before performing the reference count modifications.
170+
You may execute PHP with the ``-d opcache.protect_memory=1`` flag to mark the shared memory as
171+
read-only and trigger a hardware exception if the code accidentally attempts to modify it.
172+
173+
*****************
174+
Cycle collector
175+
*****************
176+
177+
Sometimes, reference counting is not enough. Consider the following example:
178+
179+
.. code:: php
180+
181+
$a = new stdClass;
182+
$b = new stdClass;
183+
$a->b = $b;
184+
$b->a = $a;
185+
unset($a);
186+
unset($b);
187+
188+
When this code finishes, the reference count of both instances of ``stdClass`` will still be 1, as
189+
they reference each other. This is called a reference cycle.
190+
191+
PHP implements a cycle collector that detects such cycles and frees values that are only reachable
192+
through their own references. The cycle collector will record values that may be involved in a
193+
cycle, and run when this buffer becomes full. It is also possible to invoke it explicitly by calling
194+
the ``gc_collect_cycles()`` function. The cycle collectors design is described in the `Cycle
195+
collector <todo>`_ chapter.
196+
197+
**********
198+
GC flags
199+
**********
200+
201+
.. code:: c
202+
203+
/* zval_gc_flags(zval.value->gc.u.type_info) (common flags) */
204+
#define GC_NOT_COLLECTABLE (1<<4)
205+
#define GC_PROTECTED (1<<5) /* used for recursion detection */
206+
#define GC_IMMUTABLE (1<<6) /* can't be changed in place */
207+
#define GC_PERSISTENT (1<<7) /* allocated using malloc */
208+
#define GC_PERSISTENT_LOCAL (1<<8) /* persistent, but thread-local */
209+
210+
The ``GC_NOT_COLLECTABLE`` flag indicates that the value may not be involved in a reference cycle.
211+
This allows for a fast way to detect values that don't need to be added to the cycle collector
212+
buffer. Only arrays and objects may actually be involved in reference cycles.
213+
214+
The ``GC_PROTECTED`` flag is used to protect against recursion in various internal functions. For
215+
example, ``var_dump`` recursively prints the contents of values, and marks visited values with the
216+
``GC_PROTECTED`` flag. If the value is recursive, it prevents the same value from being visited
217+
again.
218+
219+
``GC_IMMUTABLE`` has been discussed in `Immutable reference counted types`_.
220+
221+
The ``GC_PERSISTENT`` flag indicates that the value was allocated using ``malloc``, instead of PHPs
222+
own allocator. Usually, such values are alive for the entire lifetime of the process, instead of
223+
being freed at the end of the request. See the `Zend allocator <todo>`_ chapter for more
224+
information.
225+
226+
The ``GC_PERSISTENT_LOCAL`` flag indicates that a ``CG_PERSISTENT`` value is only accessibly in one
227+
thread, and is thus still safe to modify. This flag is only used in debug builds to satisfy an
228+
``assert``.

0 commit comments

Comments
 (0)