I'm a beginner in PHP. So far, from the source I'm learning from, the only mechanism to trigger an exception is by writing a line that throws it.
throw new Exception('message')
Furthermore, on the code below, any exception won't be thrown, but an error will be raised.
try
{
$file = fopen('no such file.txt', 'r');
}
catch(Exception $e)
{
echo 'Exception: ' . $e->getMessage();
}
Please give me some explanations.
It seems this try..catch block is not so useful in PHP, unlike in Java or .NET.
By convention, the functions in the PHP core do not throw exceptions (the only exception is that constructors may throw exceptions, because there's no other way for them to properly signal error conditions).
Some differences:
Exceptions have types, and you can catch them according to their type. Errors only have an associated level (E_WARNING, E_STRICT, E_NOTICE, ...).
Exceptions can be caught at any point in the call stack, otherwise they go to a default exception handler. Errors can only be handled in the defined error handler.
"errors" are remains from the pre-oop era of php and are indeed hardly useful in the modern code. Fortunately, you can (actually, must) automatically convert most "errors" to exceptions. The magic is like this
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");
Once you've got this, your "fopen" snippet will work as expected. See http://php.net/manual/en/class.errorexception.php for more details/discussion.
It is not useful in this specific case, because fopen() doesn't throw an exception when it encounters an error. I think none of the core functions do.
If you are used to working with exceptions and want to work consistently with them, I think there is nothing speaking against using the ErrorException class to turn all errors into exceptions.
However, fopen() throws only a E_WARNING when it fails to open a file, so in your example, it would be easiest to test whether $file is false to see whether the operation failed.
I personally also like to do a file_exists() before fopen(), and react accordingly if the file is missing.
Related
For concreteness, I present some code, in which what I want, I know, is not possible. I am looking for another way to get the same.
<?php
error_reporting(E_ALL | E_STRICT);
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
// When $errno is a notice, we would like a way for the execution to continue here. Since it is only a notice, eventually it could go back to where the notice was triggered.
}
set_error_handler("exception_error_handler");
Class TopLevelManagement {
private $genericInfo = "Very important to add in notices";
function highleveljob() {
try{
// In practice, the following statements could occur below in the execution tree, after a few other function calls.
$specific = new SpecificAndEncapsulated();
$specific->specificjob();
}
catch (ErrorException $e) {
$message = $e->getMessage() . $this->genericInfo;
mail($admin_email, "Consider the generic info and recover from this situation", $message);
// Here we would like the execution to continue where the exception was thrown. In the real world, this would be like "thank you error handler for SpecificAndEncapsulated::specificjob, we have taken care of the issue with the help of our larger perspective.".
}
}
}
Class SpecificAndEncapsulated {
function specificjob() {
// Some processing
if($unexpected == true) trigger_error('Here is how little I know, as I should', E_USER_NOTICE);
// Continue as expected after a notice.
}
}
?>
Of course, one solution is to pass $genericInfo as a parameter or as a global variable to SpecificAndEncapsulated::justdomyjob and let the error_handler take care of the issue without bubbling up any exception. However, this solution is not natural. There are other ways to systematically pass the variable $genericInfo to SpecificAndEncapsulated, but the issue will be the same. There should be no need to systematically pass the $genericInfo value, because it is not something that should concern SpecificAndEncapsulated, not even when an exception occurs, even less systematically at every call. A communication back to the issuer of the exception saying "thanks, now continue", after a notice has been managed at an higher level, is natural. Is there a support for this type of E_NOTICE or E_USER_NOTICE management?
Exceptions, by design, are errors after which normal execution cannot continue.
In the real world, it would go like this: a police officer (third party) calls a trucking company dispatcher (the top-level code) and says, "one of your trucks exploded in a ball of fire and the driver is in the hospital" (the job), and the dispatcher says "Noted. I expect the payload to arrive on schedule."
You have to catch exceptions inside the job if you want to continue the job. One viable approach is to pass an error handler function or a delegate object into the job.
PHP 5 has an exception model similar to that of other programming languages. An exception can be thrown, and caught ("catched") within PHP. Code may be surrounded in a try block, to facilitate the catching of potential exceptions. Each try must have at least one corresponding catch block. Multiple catch blocks can be used to catch different classes of exceptions. Normal execution (when no exception is thrown within the try block, or when a catch matching the thrown exception's class is not present) will continue after that last catch block defined in sequence. Exceptions can be thrown (or re-thrown) within a catch block.
When an exception is thrown, code following the statement will not be executed, and PHP will attempt to find the first matching catch block. If an exception is not caught, a PHP Fatal Error will be issued with an "Uncaught Exception ..." message, unless a handler has been defined with set_exception_handler().
In PHP 5.5 and later, a finally block may also be specified after the catch blocks. Code within the finally block will always be executed after the try and catch blocks, regardless of whether an exception has been thrown, and before normal execution resumes.
The thrown object must be an instance of the Exception class or a subclass of Exception. Trying to throw an object that is not will result in a PHP Fatal Error.
I am trying to use the set_error_handler function to capture require errors.
while my custom error_handler is being used, the context seems completely off, although the trace is correct.
<?php
function error_handler($errno, $errstr, $errfile, $errline){
throw new Exception($errstr);
}
set_error_handler('error_handler');
try{
trigger_error("somethign",E_USER_NOTICE);
}catch(Exception $e){
echo "I got caught";
}
try{
require "something/that/does/not/exists.php";
}catch(Exception $e){
echo "I got caught";
}
As can be seen, when I trigger the first error, it triggers the error_handler which in turn is throwing an exception. Which is caught in the first try-catch.
The second time, where I try to include an un-existing file, again the error_handler is used, but the exception is not caught.
What is going on here?
I am using php 5.5.*
Tested in CLI mode.
Just read the documentation:
require is identical to include except upon failure it will also
produce a fatal E_COMPILE_ERROR level error. In other words, it will
halt the script
(http://php.net/manual/en/function.require.php)
That means, the script execution is aborted when this error is encountered. Your custom error handler will be used but throw will be ignore because that assumes further execution which is not allowed at this point.
It's important to remember that there's two general types of errors with PHP
Processing errors are caught when your program runs
Compile errors occur when you have bad syntax or when you try to do something impossible
In your case, require is a compile error. It will not execute your user defined function because it will never get that far. The compiler can't include the bad file and will fail out.
According the PHP Manual:
Internal PHP functions mainly use Error reporting, only modern Object oriented extensions use exceptions. However, errors can be simply translated to exceptions with ErrorException
The example provided in ErrorException:
<?php
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");
It seems to allow using Exceptions instead of the default error reporting. My question is, is this an encouragement or merely an option for us?
Moreover, which is a better practice, use Exception alone like the above example, or use both Exception (set_exception_handler) and Error reporting (set_error_handler) alongside with each other?
Short answer: No. That are two different functions.
Long answer: It's not meant to replace but to make use of. set_exception_handlerDocs is used for exceptions and set_error_handlerDocs for errors. That are two different pair of shoes.
See as well:
PHP: exceptions vs errors?
PHP: What is the flow of control for error handling?
Error Handling and LoggingDocs
No, Any exception that is not caught results in a fatal error. If you want to respond gracefully to exceptions that are not caught in catch blocks, then you’ll need to set a function as the default exception handler.
To do so, you use the set_exception_handler() function, which accepts a callable as its parameter. Your script will terminate after the callable has executed.
The function restore_exception_handler() will revert the exception handler to its previous value.
Hello I have a code like that :
try
{
// Here I call my external function
do_some_work()
}
catch(Exception $e){}
The question is: If the do_some_work() has a problem and produce an Error this try catch will hide the error?
There are two types of error in PHP. There are exceptions, and there are errors.
try..catch will handle exceptions, but it will not handle errors.
In order to catch PHP errors, you need to use the set_error_handler() function.
One way to simplify things mught be to get set_error_handler() to throw an exception when you encounter an error. You'd need to tread carefully if you do this, as it has the potential to cause all kinds of trouble, but it would be a way to get try..catch to work with all PHP's errors.
If do_some_work() throws an exception, it will be catched and ignored.
The try/catch construct has no effect on standard PHP errors, only on exceptions.
produce a Fatal Error
No, catch can not catch Fatal Errors. You can not even with an error handler.
If you want to catch all other errors, have a look for ErrorException and it's dedicated use with set_error_handler:
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");
/* Trigger exception */
strpos();
Background: Suppose I have the following obviously-incorrect PHP:
try{
$vtest = '';
print(array_pop($vtest));
}catch(Exception $exx){}
For it to work with array_pop, $vtest should obviously be an array, not a string. Nevertheless, when I run this code the Warning is exhibited. I don't want that, I just want the code to fail silently.
Question: Is there something special about PHP try-catch compared to other languages that cause this not to work?
Disclaimer:
Just for reference, it is true there are other ways to handle this situation in PHP, but these are undesirable. The goal here is to avoid:
The "at-sign" trick:
$vtest = '';
print(#array_pop($vtest)); // <-- would like to avoid this
Type Casting:
$vtest = '';
$vtest = (array)$vtest;
print(array_pop($vtest));
Warnings and notices are not technically exceptions in PHP. To catch an exception it has to be explicitly thrown, and many of the built-in libraries of functions do not throw exceptions (mostly because they were written before PHP supported exceptions).
It would have been nice if somehow exceptions were built on top of the existing notice/warning/error framework but perhaps that is asking too much.
A warning will always be produced by the code you provided but you can use set_error_handler to dictate how the warning is handled; i.e. you can cause it to throw an exception. Furthermore, you can use restore_error_handler to return to default error handling when your done.
function errorHandler($errno, $errstr, $errfile, $errline) {
throw new Exception($errstr, $errno);
}
set_error_handler('errorHandler');
You can catch such errors when you convert every error to an exception. I have set up a little error-handling environment. Just test it - it will work.
The only way I can think of would be to do the following:
$vtest = '';
try{
if(!is_array($vtest)){
throw new NotArrayException();
}
print(array_pop($vtest));
}catch(NotArrayException $exx){}
Of course if you just want to do this silently you could just do the following since you don't need to catch any exception:
$vtest = '';
if(is_array($vtest)){
print(array_pop($vtest));
}