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
<mailto:php-fig+unsubscr...@googlegroups.com>.
To post to this group, send email to php-fig@googlegroups.com
<mailto:php-fig@googlegroups.com>.
To view this discussion on the web visit
https://groups.google.com/d/msgid/php-fig/ee9ba0c8-c4a4-480f-ac9b-d434f7ba64e4%40googlegroups.com
<https://groups.google.com/d/msgid/php-fig/ee9ba0c8-c4a4-480f-ac9b-d434f7ba64e4%40googlegroups.com?utm_medium=email&utm_source=footer>.
For more options, visit https://groups.google.com/d/optout.
--
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/c795abee-bedf-6867-5692-0be9f18d7217%40garfieldtech.com.
For more options, visit https://groups.google.com/d/optout.