Skip to content

Commit 0322a9e

Browse files
committed
Describe new API
1 parent 31314f0 commit 0322a9e

File tree

1 file changed

+38
-17
lines changed

1 file changed

+38
-17
lines changed

Book/php7/internal_types/functions/callables.rst

+38-17
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,19 @@ Let detail the various FCC fields:
8686
.. warning:: Prior to PHP 7.3.0 there existed an ``initialized`` field. Now an FCC is considered initialized when
8787
``function_handler`` is set to a non-null pointer.
8888

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+
8992
The *only* case where an FCC will be uninitialized is if the function is a trampoline, i.e. when the method
9093
of a class does not exist but is handled by the magic methods ``__call()``/``__callStatic()``.
9194
This is because a trampoline is freed by ZPP as it is a newly allocated ``zend_function`` struct with the
9295
op array copied, and is freed when called. To retrieve it manually use ``zend_is_callable_ex()``.
9396

9497
.. 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).
99102

100103
.. note:: To determine that two user functions are equal comparing the ``function_handler``, ``object``,
101104
``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
108111
Moreover, if a reference to the closure is kept, this must be called *prior* to freeing the closure,
109112
as the trampoline will partially refer to a ``zend_function *`` entry in the closure CE.
110113

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-
115114
Zend Engine API for callables
116115
-----------------------------
117116

@@ -120,23 +119,18 @@ We will describe the various APIs needed to deal with callables in PHP.
120119

121120
First of all, to check if an FCI is initialized use the ``ZEND_FCI_INITIALIZED(fci)`` macro.
122121

123-
.. And, as of PHP 8.3.0, the ``ZEND_FCC_INITIALIZED(fcc)`` macro to check if an FCC is initialized.
124-
125122
If you have a correctly initialized and set up FCI/FCC pair for a callable you can call it directly by using the
126123
``zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)`` function.
127124

128125
.. warning:: The ``zend_fcall_info_arg*()`` and ``zend_fcall_info_call()`` APIs should not be used.
129126
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.
133131
Moreover, as arguments to a userland call are predetermined and stack allocated it is better to assign the
134132
``params`` and ``param_count`` fields directly.
135133

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-
140134
In the more likely case where you just have a callable zval, you have the choice of a couple different options
141135
depending on the use case.
142136

@@ -176,3 +170,30 @@ functions::
176170
And specific parameter number variations for the latter.
177171

178172
.. 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

Comments
 (0)