I'm not suggesting converting all exceptions that might possibly happen
to MisconfiguredServiceException. I'm saying there's 3 broad categories:
1) What you asked for doesn't exist.
2) What you asked for is broken.
3) Something else happened, WTF? (Eg, a database-backed container has a
missing DB.)
I agree that group 3 is out of scope. Group 1 is already covered. The
question is group 2, where "there is something wrong with the container
but it's not that what you asked for is missing" is, I assert,
legitimately in scope. As someone building a framework that uses a
container I would very much care about the distinction between group 2
and group 3. That doesn't mean fully exploring all possible details of
group 2 and what might break, just indicating the separation between
groups 2 and 3.
The current text says, in essence, "for group 2, throw anything but the
same as group 1". So why even mention it then? And no, that's not a
suggestion to remove yet more things from the spec. :-) (That way lies
more incompatibility.) I'm saying there should be a clearly defined
exception for group 1, a clearly defined parent exception for group 2
(subclasses specific to a given implementation entirely welcome), and
group 3 is not-our-problem.
--Larry Garfield
On 11/07/2016 12:20 PM, Daniel Plainview wrote:
The major problem with unchecked exceptions is that it is not class
consumer business.
What do you say when someone throws SomethingIsBrokenInsideOfMe to
you? I'd say "hey, take a vacation, fix yourself, you look unhealthy".
Is it not my business what exactly is broken (leg or arm, whatever, it
doesn't help to fix my issue). But it is fair enough if library throws
YouAreWrong exception in my face when I'm screwed up.
When you make a typo in your Container implementation, it could fail
with something like \TypeError. It is "unhappy-path", isn't it? Is
it MisconfiguredServiceException? I don't think so. What do you do
then? You go and fix your implementation. What happens if
configuration is broken? You go and fix it as well. I don't see much
difference here.
MisconfiguredServiceException for me is an illusory solution for
"unhappy-path". You can't trust it. What does it exactly mean? What if
you make a syntax typo in your PHP configuration (with arrays, let's
say), should it raise the MisconfiguredServiceException? Or it should
bubble up \ParseError? I mean, it is more like
ConfigurationIsTotallyScrewedUp rather than simple
MisconfiguredService. It's vague exception that means "something is
wrong with *them*". I'd rather catch ALL other (non-NotFoundException)
exceptions if I want to avoid program crash for some reason. I can
trust \Exception (or even \Throwable). The meaning is simply same:
"something is wrong with them" and I don't really care what exactly is.
Can you please provide real-life example when you want to catch
MisconfiguredServiceException (excepting "I want to log it
differently", because it doesn't look real-life, honestly; and it is
too universal answer for any kind of exceptions)?
On Monday, November 7, 2016 at 5:27:58 PM UTC+3, Larry Garfield wrote:
Container nesting is part of the spec, and a stated goal of the
spec, so it's a valid use case to consider.
True, there are many different ways that things can break.
Consistent and constructive handling of the not-happy path is a
critical part of spec development. See also: HTML5, the majority
of which is not new stuff but standardizing the many different
ways that browsers used to handle badly formed HTML. It's a total
mess because the unhappy path was never well-defined, so everyone
did it differently, so code broke in a variety of inconsistent
ways. My issue is that "throw anything other than X" is not a
consistent and constructive handling of the non-happy path.
The biggest distinction I would draw would be between "you asked
for something that's not there" and "you asked for something
that's broken". Those are very different things; one implies I
screwed up, the other implies the configurer screwed up. I can
see the argument for not specifying a separate exception for every
possible way that the requested service is broken (there are many,
that's true), but a clear distinction between those two broad
categories ("missing" and "broken") seems like a much better baseline.
In that case, I would revise my ask to defining two exceptions:
* NotFoundException extends ContainerExceptionInterface (thrown if
the requested service isn't defined anywhere)
* MisconfiguredServiceException extends
ContainerExceptionInterface (thrown if the requested service is
defined, but for whatever reason can't be instantiated)
And implementers are free to subclass the latter if they choose,
but must still have that exception flag on them. (I'm flexible on
the name, the one I have there is likely not the best name.)
--Larry Garfield
On 11/05/2016 12:59 PM, Daniel Plainview wrote:
> A situation of "if your child container throws exception X,
you're required to catch it and turn it into anything that's not
X but is still Y" seems needlessly convoluted
You did it by introducing "child container", Container contract
doesn't have any child containers, this contract is very simple
and straightforward. By saying about child containers, you mean
that you know how internals of the Container work, you know about
"child containers", but you shouldn't care about it when you want
to use Container.
> but doesn't provide me as a developer sufficient debug
information. I'd potentially want to log differently depending
on which exception it is, but I can't do that if I have no idea
what the second exception is going to be; I just know what it's
*not* going to be, which means I'd need a Pokemon-catch if I
wanted to log it. That's what I am not comfortable with.
I asked you above, what do you think about
DependencyArgumentTypeMismatchException,
MissingRequiredArgumentException and many other exceptions, what
makes them less important than DependencyNotFoundException? They
are all about wrong configuration (or similar issues that
indicates of internal problems of Container, not user's failure).
I mean, you can say that "I'd potentially want to log differenty
DependencyArgumentTypeMismatchException and
MissingRequiredArgumentException, but I don't know how to catch
them". There are millions of reasons why container can be broken,
after all, you can't predict them all.
DependencyNotFoundException is unchecked, because it is not
client's problem, but internal issue of Container itself. Service
does exist, but configuration is wrong, client has nothing to do
with it, there is no sense to reflect it in the interface.
On Saturday, November 5, 2016 at 3:38:06 AM UTC+3, Larry Garfield
wrote:
On 11/04/2016 06:27 AM, David Négrier wrote:
I'll try an analogy with Java.
In Java, there is a difference between checked and unchecked
exceptions. Checked exceptions are the exceptions that
should be catched by the user. Unchecked exceptions are the
exceptions for which it makes no sense to catch them. There
is no reason to catch an "unchecked exception" because there
is no way the user can provide an interesting alternative
behaviour in the catch statement. So unchecked exception
should essentially always bubble up all the way to the top
of the application and trigger an exception middleware.
For PSR-11, we deemed that the NotFoundExceptionInterface
was a checked exception (because if the container does not
contain the entry you are looking for, the user can maybe
try an alternative behaviour like looking for an alias or
creating a default entry).
We also deemed that the DependencyNotFoundExceptionInterface
was an unchecked exception (because it means the container
is poorly configured and there is little to do about it
except display an error message).
Finally, we think that checked exceptions should be part of
a PSR while unchecked exceptions should be out of any PSR
(because there is no need to standardize an exception if you
don't need to catch it).
Of course, there is no absolute truth here. We could decide
that the NotFoundExceptionInterface should be "unchecked"
(because you can always call "has" before "get" so there is
no reason this exception should be catched). Also, since it
boils down to "what valid use case can I have to catch a
DependencyNotFoundExceptionInterface?", we could also find a
valid use case for catching
DependencyNotFoundExceptionInterface and decide it should be
part of the PSR. But so far, a quick survey of frameworks
out there has shown that no-one ever catches the "dependency
not found exceptions".
Also, Larry, you say:
/... based on the spec alone (no metadoc, no GitHub threads)
the following would be legal:
try {
$c1->get('a');
} catch (NotFoundExceptionInterface $e) {
print $e->getMessage();
// prints "Service 'b' not found"
}
/
This is not completely true. The spec states that:
/A call to |get| can trigger additional calls to |get| (to
fetch the dependencies). If one of those dependencies is
missing, the |NotFoundExceptionInterface| triggered by the
inner |get| call SHOULD NOT bubble out. Instead, it should
be wrapped in an exception implementing the
|ContainerExceptionInterface| that does not implement the
|NotFoundExceptionInterface|.
/
So your code example is only valid if the container decides
not to follow the recommendation (we used "SHOULD NOT"
instead of "MUST NOT" to cope with existing containers). Of
course, we could also strengthen the wording and write: /If
one of those dependencies is missing, the
|NotFoundExceptionInterface| triggered by the inner |get|
call MUST NOT bubble out./
This way, your code sample would be illegal (but it would be
harder for existing containers to implement PSR-11). I have
no strong opinion about the "SHOULD NOT" vs "MUST NOT" idea
so far. Your comments are welcome.
++
David.
See, I would disagree with dependency-not-found being an
unchecked exception. I think that's the fundamental
difference. A situation of "if your child container throws
exception X, you're required to catch it and turn it into
anything that's not X but is still Y" seems needlessly
convoluted, but doesn't provide me as a developer sufficient
debug information. I'd potentially want to log differently
depending on which exception it is, but I can't do that if I
have no idea what the second exception is going to be; I just
know what it's *not* going to be, which means I'd need a
Pokemon-catch if I wanted to log it. That's what I am not
comfortable with.
I am generally very skeptical about SHOULD, and favor MUST in
nearly all cases by default. SHOULD should be read as
"you're allowed to be incompatible here", which is a
statement a spec should make as rarely as possible.
--Larry Garfield
--
You received this message because you are subscribed to the Google Groups "PHP
Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to php-fig+unsubscr...@googlegroups.com.
To post to this group, send email to php-fig@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/php-fig/df9b6916-7b31-e4da-9eee-89892c0d1ef6%40garfieldtech.com.
For more options, visit https://groups.google.com/d/optout.