php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #72089 require() throws fatal error instead of exception
Submitted: 2016-04-23 21:28 UTC Modified: 2020-05-29 15:32 UTC
Votes:8
Avg. Score:4.4 ± 0.9
Reproduced:7 of 7 (100.0%)
Same Version:3 (42.9%)
Same OS:5 (71.4%)
From: paulobitfranca at gmail dot com Assigned:
Status: Closed Package: *General Issues
PHP Version: 7.0.5 OS: Linux
Private report: No CVE-ID: None
 [2016-04-23 21:28 UTC] paulobitfranca at gmail dot com
Description:
------------
I mind that some fatal errors are not handled by the try/catch yet.
For example, when I use require() and the include file doesn't exist.

Is it possible that in a future version, all the fatal erros can be handled by try/catch?

Test script:
---------------
<?php

	error_reporting(E_ALL);

	try
	{
    	require("xxx.php");

	}
	catch (Throwable $e)
	{
    	echo "An error: file doesn't exist"
	}

        echo "hi!";


Expected result:
----------------
An error: file doesn't exist
Hi!

Actual result:
--------------
Fatal error: require() [function.require.html: Failed opening required 'xxx.php' (include_path='.:/opt/php7/includes') in /var/www/html/teste.php on line 8

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-04-26 17:50 UTC] cmb@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: cmb
 [2016-04-26 17:50 UTC] cmb@php.net
Generally, that has already been done for PHP 7.0.0 where
reasonable and possible, see
<https://wiki.php.net/rfc/engine_exceptions_for_php7>.

With regard to your example: if a file is *required* and it can't
be included, it doesn't make much sense to go on. If on the other
hand the file is not really required, just `include` it.
 [2016-06-17 07:57 UTC] lisachenko dot it at gmail dot com
I think, that we should replace all possible places with Fatal Errors with correct throwing of Error. 

This will give us more control over the file loading process and make it more atomic, because additional checks if(file_exists($file) && is_readable($file)) generate extra stat commands and slow. Moreover, for highload project, we can hit a situation where if succeeded, but require will fail because file was deleted after check.

Code like this:
try {
    require $fileName;
} catch (Error $e) {
    echo "Oops, " . $e;
}

is much more reliable than this one:

if (file_exists($fileName) && is_readable($fileName)) {
    @include $fileName; // Silencing errors for the case of race-condition, etc
}
 [2016-06-17 09:41 UTC] cmb@php.net
-Status: Closed +Status: Re-Opened -Assigned To: cmb +Assigned To:
 [2017-06-07 09:05 UTC] mplomer at gmx dot de
> "if a file is *required* and it can't be included, it doesn't make much sense to go on."

You can say the same for a ParseError ;-)

I am currently designing a simple router where it is possible that a PHP file does not exist (to avoid a central configuration), and I want to throw a 404 then. I was happy to handle this with the new PHP 7 exception concept, as this was my first use case for it ... but then I also noticed, it just does not work for non-existent files :-(

IMHO it is really inconsistent to throw errors for parse-errors but then generate fatal errors for non-existent files.
 [2017-06-07 09:08 UTC] spam2 at rhsoft dot net
the point is with PHP7 should *anything* which is not catchable considered and handeled as bug
 [2017-06-07 09:12 UTC] spam2 at rhsoft dot net
> With regard to your example: if a file is *required* and it can't
> be included, it doesn't make much sense to go on

sorry but that is nonsense - it makes *a lot* of sense to go on with a custom error-page with some useful hint instead a blank page and when it comes to modules of your application and somewhere deep there is a require() you can't do much and by the fact that is is not catchable IT BREAKS ANY EXISTING ERROR-HANDLER and you can not do anything about it while a *parse error* in some of the includes CAN be catched - typical php inconsistency for no sane reason
 [2017-07-27 20:36 UTC] php at pointpro dot nl
In the same train of thought, why does it make sense that running foo.php, with these contents:

---------- foo.php
<?php
include "bar.php";
----------

and

---------- bar.php
<?php
asdfkoaw jeokjwe foijsdfklojsefwe
----------


Would throw a 'ParseError' exception that can be caught and handled, but when I replace the content of bar.php with the much more correct code:

---------- bar.php
<?php

class A implements B
{}
----------

Gives me a unrecoverable fatal error: Interface 'B' not found.

So a very big +1000 on making all failures in requiring files, and basically ALL errors, throw exceptions that can be caught.

Even if the script can't continue, it can do its best to provide a meaningful or at least thoughtful error message to the client.
 [2017-07-27 20:40 UTC] php at pointpro dot nl
By the way, this is issue is linked to PHP 7.0.5, but it also applies to 7.0.21, 7.1.7 and 7.2.0beta1.
 [2017-07-27 21:28 UTC] spam2 at rhsoft dot net
it's a general issue - with having Üeverything* as exception you can esily write code which handles 99.9% of all cases in a very cheap try{] while handle servers missing something in the catch part - unhandeled you get the same result as now but *you can* handle it properly
 [2017-11-28 20:48 UTC] ryan dot jentzsch at gmail dot com
As an actual case where this issue is a valid concern. Pseudocode that illustrates the issue:

<?php
try {
    SoapClient::__constructor($wsdl)
} catch (\Throwable $t) {
    // Never executed because ANYTIME the constructor can not PARSE the WSDL a script exiting fatal is thrown and not caught!
    // The SOAP implementation in PHP offers ZERO fault tolerance. 
    // We can't degrade gracefully. 
    // All processing stops and the script is exited!
    // Why in the name of sanity is a SOAP PARSE issue NOT throwing a SOAPFault and instead we get a fatal error?
}
 [2020-05-29 15:32 UTC] nikic@php.net
-Summary: handle all fatal errors with try catch +Summary: require() throws fatal error instead of exception
 [2020-05-29 15:32 UTC] nikic@php.net
Retargeting this FR for only the issue mentioned in OP, namely that require throws a fatal error. Please report separate issues for other fatal errors (after checking that there are no existing ones). Otherwise this is not actionable.

I've opened https://github.com/php/php-src/pull/5641 to address require in particular.
 [2020-06-05 07:46 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e949f306be9e7d54a700cccd5b9af9711615b43f
Log: Fixed bug #72089: Throw Error on require failure
 [2020-06-05 07:46 UTC] nikic@php.net
-Status: Re-Opened +Status: Closed
 [2022-01-03 18:39 UTC] cryptomister99 at gmail dot com
> Generally, that has already been done for PHP 7.0.0 where
> reasonable and possible, see
> <https://wiki.php.net/rfc/engine_exceptions_for_php7>.

That RFC at the beginning states: Status: Implemented (in PHP 7.0) 

However, part of the proposal in the Hierarchy section https://wiki.php.net/rfc/engine_exceptions_for_php7#hierarchy talks about BaseException. I think is out of dated (Throwable as of PHP 7.0)

Do you have an updated version of that RFC concerning PHP 7.0?
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 09:01:32 2024 UTC