@@ -86,16 +86,19 @@ Let detail the various FCC fields:
86
86
.. warning :: Prior to PHP 7.3.0 there existed an ``initialized`` field. Now an FCC is considered initialized when
87
87
``function_handler `` is set to a non-null pointer.
88
88
89
+ .. note :: As of PHP 8.3.0, the FCC holds a ``closure`` field and a dedicated API to handle storing userland callables.
90
+ This new API is described below.
91
+
89
92
The *only * case where an FCC will be uninitialized is if the function is a trampoline, i.e. when the method
90
93
of a class does not exist but is handled by the magic methods ``__call() ``/``__callStatic() ``.
91
94
This is because a trampoline is freed by ZPP as it is a newly allocated ``zend_function `` struct with the
92
95
op array copied, and is freed when called. To retrieve it manually use ``zend_is_callable_ex() ``.
93
96
94
97
.. warning :: It is not sufficient to just store the FCC to be able to call a user function at a later stage.
95
- If the callable zval from the FCI is an object (because it has an ``__invoke `` method, is a ``Closure ``,
96
- or a trampoline) then a reference to the ``zend_object `` must also be stored, the refcount incremented,
97
- and released as needed. Moreover, if the callable is a trampoline the ``function_handler `` must be copied
98
- to be persisted between calls (see how SPL implements the storage of autoloading functions).
98
+ If the callable zval from the FCI is an object (because it has an ``__invoke `` method, is a ``Closure ``,
99
+ or a trampoline) then a reference to the ``zend_object `` must also be stored, the refcount incremented,
100
+ and released as needed. Moreover, if the callable is a trampoline the ``function_handler `` must be copied
101
+ to be persisted between calls (see how SPL implements the storage of autoloading functions).
99
102
100
103
.. note :: To determine that two user functions are equal comparing the ``function_handler``, ``object``,
101
104
``called_scope ``, ``calling_scope ``, and the pointer to the ``zend_object `` for closures is generally sufficient.
@@ -108,10 +111,6 @@ op array copied, and is freed when called. To retrieve it manually use ``zend_is
108
111
Moreover, if a reference to the closure is kept, this must be called *prior * to freeing the closure,
109
112
as the trampoline will partially refer to a ``zend_function * `` entry in the closure CE.
110
113
111
- ..
112
- This API is still being worked on and won't be usable for a year
113
- note:: As of PHP 8.3.0, the FCC holds a ``closure`` field and a dedicated API to handle storing userland callables.
114
-
115
114
Zend Engine API for callables
116
115
-----------------------------
117
116
@@ -120,23 +119,18 @@ We will describe the various APIs needed to deal with callables in PHP.
120
119
121
120
First of all, to check if an FCI is initialized use the ``ZEND_FCI_INITIALIZED(fci) `` macro.
122
121
123
- .. And, as of PHP 8.3.0, the ``ZEND_FCC_INITIALIZED(fcc)`` macro to check if an FCC is initialized.
124
-
125
122
If you have a correctly initialized and set up FCI/FCC pair for a callable you can call it directly by using the
126
123
``zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) `` function.
127
124
128
125
.. warning :: The ``zend_fcall_info_arg*()`` and ``zend_fcall_info_call()`` APIs should not be used.
129
126
The ``zval *args `` parameter does *not * set the ``params `` field of the FCI directly.
130
- Instead it expect it to be a PHP array (IS_ARRAY zval) containing positional arguments, which will be reallocated
131
- into a new C array. As the ``named_params `` field accepts positional arguments, it is generally better to simply
132
- assign the HashTable pointer of this argument to this field.
127
+ Instead it expect it to be a PHP array (``IS_ARRAY `` zval) containing positional arguments,
128
+ which will be reallocated into a new C array.
129
+ As the ``named_params `` field accepts positional arguments, it is generally better to simply
130
+ assign the ``HashTable `` pointer of this argument to this field.
133
131
Moreover, as arguments to a userland call are predetermined and stack allocated it is better to assign the
134
132
``params `` and ``param_count `` fields directly.
135
133
136
- ..
137
- note:: As of PHP 8.3.0, the ``zend_call_function_with_return_value(*fci, *fcc, zval *retval)`` function has
138
- been added to replace the usage of ``zend_fcall_info_call(fci, fcc, retval, NULL)``.
139
-
140
134
In the more likely case where you just have a callable zval, you have the choice of a couple different options
141
135
depending on the use case.
142
136
@@ -176,3 +170,30 @@ functions::
176
170
And specific parameter number variations for the latter.
177
171
178
172
.. note :: If you want to call a method on an object if it exists use the ``zend_call_method_if_exists()`` function.
173
+
174
+ New FCI/FCC API in PHP 8.3.0
175
+ ----------------------------
176
+
177
+ PHP 8.3.0 added some new APIs to improve the handling and storage of FCCs and userland callables.
178
+ This was achieved by adding the ``closure `` field to the FCC.
179
+
180
+ First of all a new ``ZEND_FCC_INITIALIZED(fcc) `` macro to check if an FCC is initialized was added,
181
+ this is helper similar to the ``ZEND_FCI_INITIALIZED(fci) `` macro.
182
+
183
+ The ``zend_fcc_addref() `` and ``zend_fcc_dup() `` functions will do all the necessary reference increments
184
+ to safely store an FCC in an internal object.
185
+ The ``zend_fcc_equals() `` function, can be used if two FCCs are equal or not, which also supports trampolines.
186
+ The ``zend_fcc_dtor() `` function must be used when releasing an FCC that was copied for internal storage.
187
+
188
+ If an internal object stores an FCC the ``get_gc `` object handler must be defined,
189
+ and add it to the GC buffer via ``zend_get_gc_buffer_add_fcc() ``.
190
+
191
+ The ``zend_get_callable_zval_from_fcc() `` function will create a callable zval that can be returned to userland.
192
+
193
+ When calling a stored FCC the
194
+ ``void zend_call_known_fcc(zend_fcall_info_cache *fcc, zval *retval_ptr, uint32_t param_count, zval *params, HashTable *named_params) ``
195
+ should be used, as it will duplicate the op array of a trampoline.
196
+ The remaining parameters will be used to construct the FCI.
197
+
198
+ .. note :: The ``zend_call_function_with_return_value(*fci, *fcc, zval *retval)`` function was also added in PHP 8.3.0
199
+ to replace the usage of ``zend_fcall_info_call(fci, fcc, retval, NULL) ``.
0 commit comments