[DOC-CVS] [doc-en] master: errorfunc: document the error handler stack (#5253)
[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-25T22:16:49+02:00
Commit: https://github.com/php/doc-en/commit/cbfc5d5d55d682c185583561295462a6d5ca0ea1
Raw diff: https://github.com/php/doc-en/commit/cbfc5d5d55d682c185583561295462a6d5ca0ea1.diff
errorfunc: document the error handler stack (#5253)
set_error_handler() saves the handler that was active until then on an
internal stack and installs the new one in its place;
restore_error_handler() pops the saved one back, together with the
error_levels mask it was registered with. Neither page said so, which
invites restoring the previous handler by passing the return value of
set_error_handler() back to it. That grows the stack instead of
shrinking it, and resets error_levels to E_ALL.
Adds a caution against that pattern and an example calling the previous
handler from the new one. The seealso simplelists are unwrapped from
their para, matching the exception handler pages.
Changed paths:
M reference/errorfunc/functions/restore-error-handler.xml
M reference/errorfunc/functions/set-error-handler.xml
Diff:
diff --git a/reference/errorfunc/functions/restore-error-handler.xml b/reference/errorfunc/functions/restore-error-handler.xml
index 31cbc6c532bb..a374b5de3820 100644
--- a/reference/errorfunc/functions/restore-error-handler.xml
+++ b/reference/errorfunc/functions/restore-error-handler.xml
@@ -12,11 +12,17 @@
<type>true</type><methodname>restore_error_handler</methodname>
<void/>
</methodsynopsis>
- <para>
- Used after changing the error handler function using
- <function>set_error_handler</function>, to revert to the previous error
- handler (which could be the built-in or a user defined function).
- </para>
+ <simpara>
+ Pops the error handler that was active before the most recent call to
+ <function>set_error_handler</function> off the internal stack of error
+ handlers and makes it active again, together with the
+ <parameter>error_levels</parameter> mask it was registered with.
+ The restored handler could be the built-in or a user defined function.
+ </simpara>
+ <simpara>
+ Calling this function more often than <function>set_error_handler</function>
+ leaves the built-in error handler active; no error is raised.
+ </simpara>
</refsect1>
<refsect1 role="parameters">
@@ -67,15 +73,13 @@ Invalid serialized value.
<refsect1 role="seealso">
&reftitle.seealso;
- <para>
- <simplelist>
- <member><function>error_reporting</function></member>
- <member><function>set_error_handler</function></member>
- <member><function>get_error_handler</function></member>
- <member><function>restore_exception_handler</function></member>
- <member><function>trigger_error</function></member>
- </simplelist>
- </para>
+ <simplelist>
+ <member><function>error_reporting</function></member>
+ <member><function>set_error_handler</function></member>
+ <member><function>get_error_handler</function></member>
+ <member><function>restore_exception_handler</function></member>
+ <member><function>trigger_error</function></member>
+ </simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
diff --git a/reference/errorfunc/functions/set-error-handler.xml b/reference/errorfunc/functions/set-error-handler.xml
index f425fd317229..aa620d26cc20 100644
--- a/reference/errorfunc/functions/set-error-handler.xml
+++ b/reference/errorfunc/functions/set-error-handler.xml
@@ -13,10 +13,13 @@
<methodparam><type class="union"><type>callable</type><type>null</type></type><parameter>callback</parameter></methodparam>
<methodparam choice="opt"><type>int</type><parameter>error_levels</parameter><initializer><constant>E_ALL</constant></initializer></methodparam>
</methodsynopsis>
- <para>
- Sets a user function (<parameter>callback</parameter>) to handle
- errors in a script.
- </para>
+ <simpara>
+ Sets a user function (<parameter>callback</parameter>) to handle errors in
+ a script.
+ The handler that was active until then is saved on an internal stack of
+ error handlers, from which <function>restore_error_handler</function> pops
+ it back.
+ </simpara>
<para>
This function can be used to define custom error handlers during runtime,
for example in applications which need to do file/data cleanup when a critical
@@ -62,10 +65,13 @@
<varlistentry>
<term><parameter>callback</parameter></term>
<listitem>
- <para>
- If &null; is passed, the handler is reset to its default state.
+ <simpara>
+ If &null; is passed, no user-defined handler is left active and errors
+ fall back to the built-in error handler.
+ The handler that was active until then is still saved on the stack and
+ can be brought back with <function>restore_error_handler</function>.
Otherwise, the handler is a callback with the following signature:
- </para>
+ </simpara>
<para>
<methodsynopsis>
<type>bool</type><methodname><replaceable>handler</replaceable></methodname>
@@ -329,24 +335,83 @@ vector d - fatal error
<b>My ERROR</b> [256] log(x) for x <= 0 is undefined, you used: scale = -2.5<br />
Fatal error on line 35 in file trigger_error.php, PHP 5.2.1 (FreeBSD)<br />
Aborting...<br />
+]]>
+ </screen>
+ </example>
+ </para>
+ <para>
+ <example>
+ <title>Calling the previous handler from the new one</title>
+ <simpara>
+ The return value of <function>set_error_handler</function> is the handler
+ that was active until then. Calling it from the new handler keeps the
+ existing behaviour while adding to it. This only works if that handler is
+ a user defined function; &null; is returned when the built-in one was
+ active.
+ </simpara>
+ <programlisting role="php">
+<![CDATA[
+<?php
+function logging_handler(int $errno, string $errstr): bool
+{
+ echo "logged: $errstr\n";
+ return true;
+}
+
+set_error_handler('logging_handler');
+
+$previous = set_error_handler(function (int $errno, string $errstr) use (&$previous): bool {
+ echo "counted: $errstr\n";
+ return $previous !== null ? $previous($errno, $errstr) : false;
+});
+
+trigger_error("something happened", E_USER_WARNING);
+
+restore_error_handler();
+trigger_error("only logged now", E_USER_WARNING);
+
+restore_error_handler();
+?>
+]]>
+ </programlisting>
+ &example.outputs;
+ <screen>
+<![CDATA[
+counted: something happened
+logged: something happened
+logged: only logged now
]]>
</screen>
</example>
</para>
</refsect1>
+ <refsect1 role="notes">
+ &reftitle.notes;
+ <caution>
+ <simpara>
+ Do not revert to the previous handler by passing the return value of
+ <function>set_error_handler</function> back to it.
+ Doing so pushes a further entry onto the stack instead of removing one,
+ so the stack grows without bound in loops and long-running processes, and
+ <parameter>error_levels</parameter> is reset to <constant>E_ALL</constant>,
+ silently widening the range of errors the restored handler receives.
+ <function>restore_error_handler</function> is the intended way to revert
+ to the previous handler.
+ </simpara>
+ </caution>
+ </refsect1>
+
<refsect1 role="seealso">
&reftitle.seealso;
- <para>
- <simplelist>
- <member><classname>ErrorException</classname></member>
- <member><function>error_reporting</function></member>
- <member><function>restore_error_handler</function></member>
- <member><function>get_error_handler</function></member>
- <member><function>trigger_error</function></member>
- <member><link linkend="errorfunc.constants">error level constants</link></member>
- </simplelist>
- </para>
+ <simplelist>
+ <member><exceptionname>ErrorException</exceptionname></member>
+ <member><function>error_reporting</function></member>
+ <member><function>restore_error_handler</function></member>
+ <member><function>get_error_handler</function></member>
+ <member><function>trigger_error</function></member>
+ <member><link linkend="errorfunc.constants">error level constants</link></member>
+ </simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file