Is there any way around the "parse error of death"? - php

I'm pretty sure I'm not only one who has noticed that simple parse errors on PHP, if present in very nested scenarios (eg, an object instance which references another object instance which references another object instance that has a very tiny parse error, all of them being auto loaded) can make PHP hang forever instead of reporting the parse error and halting the execution like it would normally do — I've seen this many times and in very different code bases, always with the proper error_reporting setting set.
Is there any way around it? i.e., can it be forced to display the parse error report as it should somehow?
For the record, I'm 100% sure these hangs were caused as a result of PHP not handling the parse error correctly, as I have debugged this behaviour many times; the reason I ask is because when these hangs happen one is basically left in the dark, not even being able to tell whether PHP is acting funny or there really is an malfunctioning loop in the code somewhere — this takes time to debug, time that could be saved if, you know, PHP reported the parse error like it should.

As partially mentioned in the comments, error_reporting(E_ALL) can help display all errors. You might also have to use ini_set and make display_errors have a value of on.
Personally, I think your question is not very clear, and you should improve formatting and make it more understandable.
UPDATE: Your server / computer you're running the code on seems to be very slow. No 'hanging-around' should really occur. Or could you describe it with further detail?
Also, you might be stuck in an infinite or near-infinite loop. Check closely in your code, because unless you post all your code, this is the limit to which we can help you.
UPDATE 2: It seems that you may have mistyped the name of an object when you are trying to call it. Otherwise, it may be that you have not declared your object correctly.
Most likely one or the other.

Turns out the culprit was xdebug.collect_params, which the documentation very correctly suggests to keep disabled. Certain errors were simply generating a very large amount of data in the arguments of the call stack trace which exhausted xdebug with collect_params set to 4 and made xdebug and by extension PHP to hang, even though I have a custom exception handler in place which never actually retrieves the stack trace from xdebug, but apparently xdebug collects this data anyway.
This was hard to debug because: a) it was not straightforward to replicate b) profiling with xdebug did not help c) stepping through the code with xdebug + dbgp was not helping either d) almost no trace (no pun intended) was left other than very ocasionally logging the errors to the php error_log file and e) with a custom exception handler it was not obvious to suspect of xdebug, since I didn't involve it in the process of handling the exception, or so I thought.
So there is no such thing as the parse error of death, and I learned to never assume it's not my fault :) Hopefully this answer will help others in the future at least.

Related

Can I really do nothing with fatal parse errors?

Beginner question: I have done around 30 hours trying to sort out an error handler, essential as I am not a great programmer. I am 95% sure I can’t do anything about fatal-fatal errors but I am still 5% hopeful.
My error handler was working well sending out emails and text messages when it encounters problems but then I got an empty page with just:
Fatal error: Cannot use try without catch or finally
in /directory/ etc ...filename.php on line 999
(I had accidentally deleted the catch block.) The question: Someone somewhere mentioned htaccess 500 pages.
I did not understand what was described when I read it. I have done almost nothing with htaccess up to now.
Is there a way to trip some sort of static page? (I am 95% sure I can do nothing but I am stuck and still have a 5% hope and this is really important for me.) I am still running PHP 5.6 but do not want to upgrade to 7 yet. Catching these errors is far more important for me than the warnings, notices, deprecateds etc that I can catch.
Update
I saw that question and used some of the techniques there BUT it is 11 years old, huge, partly outdated and does NOT primarily address the problem I now want to solve.
I have no problem dealing with "fatal errors" such as calling a non existent function. My problem is about errors found when the script is parsed and are "unrecoverable". In my case a missing catch when a try is present.
The other answer, answers this in parts but not in ways that I can seem to use. I think there maybe a way of forcing a 500 error rather perversely by stopping error display which I will investigate soon/tomorrow. I would be grateful for 24 hours to check. I am quite happy for someone more knowledgeable to put up a better question/answer and useful info could be culled from that thread but, frankly it is a mess unsurprisingly after 11 years.
Answer - almost
Switch display_errors to off and you have a 500 error. Sadly I cannot get an .htaccess redirect to work (404 works fine). If you are good with .htaccess hopefully you will have some joy.
In some discussions there is talk of some 500 errors being "CORE" errors and REALLY unrecoverable even by .htaccess. My logs are very sparse and I cannot see any useful indication if this is the case for the catch when a try is present error.
(With a big thank you to #Dharman (if it works)). PS Will tidy this up when/if I get to the end of this.)
I don't think PHP can do anything with parse errors (or other errors during the compilation phase), but you should be able to configure your web server to display an error page of your choosing.
You don't say what web server you are using, but for example with Apache these are the Custom Error Response settings. Your errors will be HTTP 500 errors.

Slim error handling

The Slim Framework is good - seriously good. One of the issues I have run into is with the way it handles errors. In vanilla PHP code I occasionally use trigger_error statements as a debug aid. In vanilla PHP this has no untoward consequences since by default trigger_errors are E_USER_NOTICE type errors that do not stop the script dead in its tracks. However, in Slim things appear to work differently. A benign trigger_error causes it to throw a wobbly and an HTTP 500 is returned.
I thought this could be corrected by
Changing the mode to development or something but the docs state that this makes no difference whatsoever to the way Slim works internally.
Next port of call - changing the slim error logging level
$app = new \Slim\Slim(array('log.level' => \Slim\Log::ERROR);
does not quite have the same effect as PHP's error_reporting. Setting it stops the error from floating up to the error.log file (the default error logger used by Slim) but crucially it does not stop the HTTP 500.
I have come across forum posts that suggest replacing the default Slim::handleErrors method. That would be easy but I wonder if that is not incorrect. What is the right way to stop Slim coming to a dead halt when it runs into a wholly innocuous trigger_error? I can well avoid this but I may rely on other code that may have such statements. I would much appreciate any help
The answer turns out to be quite simple. I figured it out by checking out the handleErrors function in slim.php. Just issue a
error_reporting(E_ALL & ~E_USER_WARNING);
prior to where the trigger_error is called and you are in business. Somewhere down the line Slim is changing the default PHP error_reporting to include E_USER_WARNING.

Changing PHP error_log behaviour possible?

I'm wondering if it's possible to change the default behaviour of PHP's error_log() functionality to include the source and originating line number by default.
I am guessing this could be potentially be done either with a PHP ini setting or by configuring apache in some specific way, though not being an apache guru I'm not sure how this would be made possible.
In my default environment, finding the source of the errors in a log generally doesn't pose too much of a problem where the error is legitimately spawned by a PHP warning or notice, as it will report automatically where the line originates... however, calls made manually by programmers to PHP error_log() don't do this, and I can't find a way to make this behavior default.
I am aware that generally speaking you can achieve the line reporting manually with the magic constant like this:
error_log("Failed to login to MySQL ".__LINE__);
However, I am curious and open to suggestions about if there are any ways to perhaps configure the way errors are reported universally in the log or anything else to get around changing every single call in code to include the magic constant.
You can define your own error handler using the set_error_handler function. This allows you to do with the errors whatever you like, as long as it is within the scope of PHP language (including printing the file and line where the error occured). Most common course of action in this case is to convert the error into a ErrorException.
Also you can use tools like xDebug, which, when activated in php.ini, display the errors in more readable form.

White page even with full error_reporting and display_errors

I have a really, really weird situation here. I'm working on a local development server with Zend Server installed. I have full error reporting and display errors, but I'm still getting a white page. Of course, I understand that i've done something wrong, but i want to have an idea WHAT it is i've done wrong.
The system i'm currently working on depends heavily on classes, includes and so on, therefore i can't simply "check" a page (i.e. run it standalone, outside the system, call it directly and stuff). That just won't work.
I've checked the syntax, that's not the problem. I'm stuck, and want to see my errors. If you have any ideas, please tell me!
Just to make clear, I'm already using the following:
ini_set('display_errors', true); error_reporting(-1);
After using an own error handler (php.net/set_error_handler) and some hard debugging (echo's, exits and so on), i found out that i was overruling a variable that was used later on. The variable used to be an object, but was now an int. Weird though that there wasn't any error about the fact that i was calling a function on non-object...
Very weird, but i'm glad that i've found the bug in my application.
You should be able to set the error log in your php.ini. Everything should be properly listed there. We use that approach for some of our sites, since we do not want customers to be able to see error messages on production servers.
try logging what key variables are in several of the classes. Worst case scenario, throw in some echo statements here and there just to stay sane.
error_log(print_r($var, true));

On what line did a script exit?

I have a php script that is rather hairy and I'm trying to troubleshoot it. No errors are happening, but I'm having trouble seeing what execution path it took to create the output I've gotten. Is there a way I can see at what line the script stopped execution?
Folks, sorry I didn't make this clearer. No errors are happening. No exceptions are being raised. From a computer point of view, nothing 'bad' is happening. But the output is not what I'm expected. I'm trying to track down where exactly the script is exiting normally, but it's a challenge. My life would be much easier if it said something like "Script finished parsing at line 422".
Using Xdebug and running a function trace should give you the info you're looking for.
I'm not sure I'm completely understanding the question. An exception is being thrown and the program is terminating but there is no output?
Try turning error reporting on to the most sensitive level:
error_reporting(E_ALL)
If an error occurs, there is an error message (except for a small number of parse errors). As Brad already suggests, turn up the volume on your error reporting first.
Otherwise, the script will run until its end, or a exit or die() command. I don't think it's possible to find out where a script was exited, but then, it should never be really necessary to.
When debugging hairy errors, either use a debugger and/or debug_backtrace(). Debug_backtrace() can give you the exact call stack. It's most powerful in combination with a custom_error_handler().

Categories