-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Throwable Interface #1284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Throwable Interface #1284
Conversation
Added Throwable interface that exceptions must implement in order to be thrown. BaseException was removed, EngineException renamed to Error, and TypeException and ParseException renamed to TypeError and ParseError. Exception and Error no longer extend a common base class, rather they both implement the Throwable interface.
👍 |
Soap extension can use other API functions.
@trowski This looks even better, I think. 👍 |
the only concern of mine here is, the Error is too simple, it probably be wildly used... but I admit that this is much better than current implementation. |
For catching all errors, catch(Throwable $stone){ // WAT
// you know, consistency
$this->getMedievalLogger->siege()->logThrew($stone);
} It doesn't say anything about the error severity. It's fine for tools such as PHPUnit but In my opinion there should be only one major type and it's Error:
Focus on this pls: At the end of the day, an unresolved/unhandled Exception is an Error that you want to log/debug. If an Exception doesn't get caught by any |
if you don't like Error, Failure could be fine:
Also, i find |
also don't forget about (current name) AssertionException. as I just told you in room11, failed preconditions are considered programming errors, so:
try{
try{
assert(isset($lol))
$foo = $this->getFoo($lol);
}catch(Exception $e){
$foo = $this->createFoo($lol);
}
$foo->run();
}catch(Failure $e){
$logger->log($e);
} |
@WesNetmo:
|
@Kubo2 i've already answered your question here #1284 (comment) |
@WesNetmo Yeah, but from there I think the best name for the interface is |
@Kubo2 no pls. this is not c# |
The name Conceptually both of these conditions are error conditions detected by PHP. The only difference is that for some errors the execution of the script can continue from where the error occurred; for others it is not possible for execution to continue from the place where the error occurred, and so instead an exception must be thrown. While this name may also cause some confusion for users, other name choices such as |
What is the status of this? Looks like discussion has settled down, and PHP 7 Alpha 1 should be tagged in 9 days from now, would be nice to get this change in (or Alpha 2 at least). |
@Majkl578 Voting for this RFC ends on June 24th. I guess we will see this in the next release after that date. |
@weltling No problem, I'll do this later today. |
# Conflicts: # Zend/zend_language_scanner.c # Zend/zend_language_scanner.l # ext/simplexml/tests/SimpleXMLElement_xpath.phpt
@weltling All conflicts resolved and tests updated to use revised exception names, plus updated the previous parameter to accept any |
@@ -925,7 +926,7 @@ ZEND_API void zend_exception_error(zend_object *ex, int severity) /* {{{ */ | |||
|
|||
zend_string_release(file); | |||
zend_string_release(message); | |||
} else if (instanceof_function(ce_exception, base_exception_ce)) { | |||
} else if (instanceof_function(ce_exception, default_exception_ce) || instanceof_function(ce_exception, error_ce)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd check throwable_ce
here instead.
Also moved REGISTER_ITERATOR_INTERFACE macro to zend_interfaces.h and renamed it to REGISTER_INTERFACE.
instead. As EngineException extends BaseException but not Exception, these | ||
exceptions will not caught by existing try/catch blocks. | ||
* Some fatal errors and recoverable fatal errors now throw an Error instead. | ||
As Error is a separate class from Exception, these exceptions will not caught |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will not be caught?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, thanks.
Renamed REGISTER_INTERFACE (formerly REGISTER_ITERATOR_INTERFACE) to REGISTER_MAGIC_INTERFACE and renamed REGISTER_ITERATOR_IMPLEMENT to REGISTER_MAGIC_IMPLEMENT. Both have now been moved to zend_interfaces.h.
@trowski, please don't change this pull request, i've already started to merge/test what was in prior to the Andrea's comment. You can create another PR after this one is merged. Thanks. |
@trowski, merged, thanks for your work! |
🚀 |
🆗 👯 |
@trowski Can you please explain when will I couldn't find such information on this thread or on the RFC. Thanks :) . |
@SoboLAN I wrote a short blog post about the new exception hierarchy in PHP 7 that answers your questions: Throwable Exceptions and Errors in PHP 7 |
Is there any chance to extend the interface with a Just consider following code fragment: } catch (SomeOtherException $e1) {
try {
$this->pdo->rollback();
throw new \DomainException("Failed", 0, $e1);
} catch (\PDOException $e2) {
// $e2 is lost!
throw new \DomainException("Failed even more", 0, $e1);
}
} The last catch block has now a $e1 and $e2 which need to be propagated by the DomainException. But $e2 gets lost. |
@malkusch This could easily be implemented in user code: interface ThrowableWithSuppressed extends Throwable
{
public function addSuppressed(Throwable $exception);
public function getSuppressed(): array;
}
class MyException extends Exception implements ThrowableWithSuppressed
{
private $suppressed = [];
public function addSuppressed(Throwable $exception)
{
$this->suppressed[] = $exception;
}
public function getSuppressed(): array
{
return $this->suppressed;
}
public function __toString(): string
{
$string = parent::__toString();
if (!empty($this->suppressed)) {
$string .= "\n";
foreach ($this->suppressed as $exception) {
$string .= "\nSuppressed " . $exception;
}
}
return $string;
}
}
try {
throw new Exception('1');
} catch (Exception $e1) {
try {
throw new Exception('2');
} catch (Exception $e2) {
$e = new MyException('3', 0, $e1);
$e->addSuppressed($e2);
throw $e;
}
} Note that if an exception is created while a thrown exception already exists, the previously thrown exception is automatically set to the previous exception. For example: try {
throw new Exception('1');
} finally {
throw new Exception('2');
}
|
Sure, but this doesn't help if I have to handle cases which are out of my domain.
Oh that's sweet. I didn't expect that. Thank you, that's very good to know. But don't you think that's odd? There's no causality between Exception("1") and Exception("2"). But maybe that's OK as in PHP it's called |
Libraries that have patterns like you've outlined could define an exception class with a list of suppressed exceptions, otherwise it isn't necessary. However, I see your point, as it would be a common pattern and therefore might be useful to be included in the base exception classes.
Admittedly it is a little magical that the first exception is set to the previous exception for the second, but isn't much different than magically adding the exception to a list of suppressed exceptions. I see you started a discussion on internals, so this can continue there. |
This pull request is a variant based on my prior pull request after getting some input from @nikic. I believe this is closer to what @sebastianbergmann wanted to accomplish in his Throwable pull request.
I'm proposing a modification to the exception hierarchy for PHP 7:
This hierarchy is similar to my last pull request, with some notable changes:
Throwable
interface.BaseException
or any similar class has been eliminated.Error
replacesEngineException
in the current implementation.Throwable
cannot be implemented by user space classes, so onlyException
orError
can be thrown.User code can catch these classes separately or catch them all with
Throwable
.catch(Exception $e)
does not catch any previously uncaught exceptions.catch(Error $e)
can be used to catch engine, type, or parse errors.catch(Throwable $e)
can catch any throwable class.This proposed hierarchy provides a clearer separation of thrown classes.
Error
is only thrown due to problems that previously raised errors. TheError
naming scheme was chosen to avoid confusion. Example: why wouldcatch (Exception $e)
not catch an object namedEngineException
? However changing them back toEngineException
, etc. or any other name such asFailure
would certainly be up for discussion.