[DOC-CVS] [doc-en] master: Document the exception handler stack behavior of PHP 8.3.0 and 8.3.5 (#5222)
[email protected] (Louis-Arnaud via GitHub)
| Newsgroups | php.doc.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: Louis-Arnaud (lacatoire)
Committer: GitHub (web-flow)
Pusher: lacatoire
Date: 2026-08-25T11:24:23+02:00
Commit: https://github.com/php/doc-en/commit/1cc803aaa07ac94ce8e3bfdf56f4b9ddd23326d3
Raw diff: https://github.com/php/doc-en/commit/1cc803aaa07ac94ce8e3bfdf56f4b9ddd23326d3.diff
Document the exception handler stack behavior of PHP 8.3.0 and 8.3.5 (#5222)
Changed paths:
M reference/errorfunc/functions/restore-exception-handler.xml
M reference/errorfunc/functions/set-exception-handler.xml
Diff:
diff --git a/reference/errorfunc/functions/restore-exception-handler.xml b/reference/errorfunc/functions/restore-exception-handler.xml
index 0ccf779c33a0..a2d8251b5fcc 100644
--- a/reference/errorfunc/functions/restore-exception-handler.xml
+++ b/reference/errorfunc/functions/restore-exception-handler.xml
@@ -20,6 +20,27 @@
exception handler (which could be the built-in or a user defined
function).
</para>
+ <note>
+ <simpara>
+ While an exception handler is running, no exception handler is active: as of
+ PHP 8.3.0 the engine unsets it before invoking it, so that an exception
+ thrown by the handler is not passed back to it.
+ </simpara>
+ <simpara>
+ As of PHP 8.3.5 the engine also pushes the handler it is about to invoke onto
+ the handler stack. A <function>restore_exception_handler</function> call made
+ from within an exception handler therefore pops that entry and re-installs
+ the handler that is currently running; a second call is needed to install the
+ handler that was active before it.
+ </simpara>
+ <simpara>
+ The running handler is re-installed automatically when it returns, but only
+ if no exception handler is active at that point: a handler that calls
+ <function>set_exception_handler</function> or
+ <function>restore_exception_handler</function> is left in charge of the
+ handler stack itself.
+ </simpara>
+ </note>
</refsect1>
<refsect1 role="parameters">
@@ -34,6 +55,40 @@
</para>
</refsect1>
+ <refsect1 role="changelog">
+ &reftitle.changelog;
+ <para>
+ <informaltable>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>&Version;</entry>
+ <entry>&Description;</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>8.3.5</entry>
+ <entry>
+ The exception handler being invoked is now pushed onto the handler
+ stack, so <function>restore_exception_handler</function> called from
+ within an exception handler re-installs the handler that is currently
+ running; restoring the handler that was active before it now requires
+ two calls.
+ </entry>
+ </row>
+ <row>
+ <entry>8.3.0</entry>
+ <entry>
+ The active exception handler is now unset while it runs.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </refsect1>
+
<refsect1 role="examples">
&reftitle.examples;
<para>
@@ -70,18 +125,16 @@
</example>
</para>
</refsect1>
-
+
<refsect1 role="seealso">
&reftitle.seealso;
- <para>
- <simplelist>
- <member><function>set_exception_handler</function></member>
- <member><function>get_exception_handler</function></member>
- <member><function>set_error_handler</function></member>
- <member><function>restore_error_handler</function></member>
- <member><function>error_reporting</function></member>
- </simplelist>
- </para>
+ <simplelist>
+ <member><function>set_exception_handler</function></member>
+ <member><function>get_exception_handler</function></member>
+ <member><function>set_error_handler</function></member>
+ <member><function>restore_error_handler</function></member>
+ <member><function>error_reporting</function></member>
+ </simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
diff --git a/reference/errorfunc/functions/set-exception-handler.xml b/reference/errorfunc/functions/set-exception-handler.xml
index ce282ee63515..df06f4462c14 100644
--- a/reference/errorfunc/functions/set-exception-handler.xml
+++ b/reference/errorfunc/functions/set-exception-handler.xml
@@ -19,6 +19,32 @@
try/catch block. Execution will stop after the
<parameter>callback</parameter> is called.
</para>
+
+ <note>
+ <simpara>
+ While an exception handler is running, no exception handler is active: as of
+ PHP 8.3.0 the engine unsets it before invoking it, so that an exception
+ thrown by the handler is not passed back to it. Called from within a handler,
+ <function>set_exception_handler</function> therefore reports no previously
+ defined handler.
+ </simpara>
+ <simpara>
+ As of PHP 8.3.5 the engine also pushes the handler it is about to invoke onto
+ the handler stack, so <function>restore_exception_handler</function> called
+ from within a handler re-installs the handler that is currently running
+ rather than the one that was active before it.
+ </simpara>
+ <simpara>
+ The running handler is re-installed automatically when it returns, but only
+ if no exception handler is active at that point. As soon as the handler calls
+ <function>set_exception_handler</function> or
+ <function>restore_exception_handler</function>, this automatic restoration is
+ skipped and the active handler is whatever the handler itself left in place.
+ </simpara>
+ <simpara>
+ Modifying the exception handler from within itself is therefore discouraged.
+ </simpara>
+ </note>
</refsect1>
<refsect1 role="parameters">
@@ -59,6 +85,40 @@
</para>
</refsect1>
+ <refsect1 role="changelog">
+ &reftitle.changelog;
+ <para>
+ <informaltable>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>&Version;</entry>
+ <entry>&Description;</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>8.3.5</entry>
+ <entry>
+ The exception handler being invoked is now pushed onto the handler stack
+ and re-installed once it returns, unless the handler modified the stack
+ itself.
+ </entry>
+ </row>
+ <row>
+ <entry>8.3.0</entry>
+ <entry>
+ The active exception handler is now unset while it runs, so
+ <function>set_exception_handler</function> called from within a handler
+ reports no previously defined handler.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </refsect1>
+
<refsect1 role="examples">
&reftitle.examples;
<para>
@@ -84,15 +144,13 @@ echo "Not Executed\n";
<refsect1 role="seealso"><!-- {{{ -->
&reftitle.seealso;
- <para>
- <simplelist>
- <member><function>get_exception_handler</function></member>
- <member><function>restore_exception_handler</function></member>
- <member><function>restore_error_handler</function></member>
- <member><function>error_reporting</function></member>
- <member><link linkend="language.exceptions">Exceptions</link></member>
- </simplelist>
- </para>
+ <simplelist>
+ <member><function>get_exception_handler</function></member>
+ <member><function>restore_exception_handler</function></member>
+ <member><function>restore_error_handler</function></member>
+ <member><function>error_reporting</function></member>
+ <member><link linkend="language.exceptions">Exceptions</link></member>
+ </simplelist>
</refsect1><!-- }}} -->
</refentry>