-
-
Notifications
You must be signed in to change notification settings - Fork 312
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
container->has(..) false positive #847
Comments
Also noticed, that 'FetcheDefinitions" property of container has no "Gt\PaymentToDriver\TopAccount" key before ->has('Gt\PaymentToDriver\TopAccount'), and has it after such checking. Maybe its normal. But my goal is to set the container entry IF it was NOT set before. The ->getKnownEntryNames() does not contain 'Gt\PaymentToDriver\TopAccount', but has(Gt\PaymentToDriver\TopAccount) show True. The ->debugEntry(TopAccount::class) shows:
But I did not set 'Gt\PaymentToDriver\TopAccount' in container - by set() or thru container definitions. |
The PSR container interface definition states: https://www.php-fig.org/psr/psr-11/#112-reading-from-a-container
"Known to the container" is quite easy to determine if the container requires explicit definition of every entry it shall create, but the beauty of PHP-DI is the autowiring which enables it to create much more classes than are explicitly defined. Returning I am quite convinced discussing the motivation for you to do what you intend would reveal that you try to configure the DI container "later", once some additional information has been gathered and now is supposed to be stored back into the container for future use. I personally would object such an approach, as my understanding of the role of a DI container is to be created/configured with some defineable set of configuration data (including strings for URLs, usernames, passwords), and then this container is not changing anymore, but only handing out objects to work on whatever task is to be done. If "dynamic" objects have to be created that depend on the actual data that is to be processed, this is not the task of a DI container, but should be done by some specific factory object - which itself may be injected into position by the DI container. |
Good evening! Thank you for explanation. You are right, I try to use container as a cache to share the object between calls of different methods/procedures. I will use strict string IDs for has() args instead of class strings, to be sure that IDs is surely is 'unknown' for container. Besides of that, just a note: |
So, currently it is no method to be sure that an object is retrievable by class string(ClassName::class). currently it is possible only by regular string. Unfortunately. |
Exactly. We are talking about two distinct things here. PHP-DI does attempt to verify with low effort whether or not the container knows about a requested class, however it does not do the full run of actually instantiating the object, as that would potentially be the full recursive autowiring required, which might be too much of a performance impact. And I can see that returning Using any other DI container that is forcing you to provide an explicit configuration for every class you want to fetch has a much easier time figuring out if an entry for something exists. PHP-DI would be forced to identify whether or not the whole potential recursive class tree is buildable - it's barely a matter of "obviously it could detect there is a string parameter missing on the top level, why not use that info to return My recommendation would be to use a wrapper class for your missing info instead. Inject a class that can then be queried whether or not it already has your class, and can thruthfully answer yes or no, and then offer a method to inject a new instance into. That is offloading your requirement away from the container back into your own code's responsibility, it is explicit in a way that makes it obvious a value isn't present at the time the container is started, but has to be fetched later. Much like the PSR interfaces for request and response - they are also usually not created within the DI container, but a request factory is being fetched from the container in case a request has to be created. |
Thank you @SvenRtbg! I am not such a qualified developer to discuss this subject with you detailed. But, even after your answer I still tormented by two simple riddles:
I cannot imagine people for whom this info from container is useful: "I know about this class, but cannot say if you can get it"
if ->has(ClassName::class) affects performance, why ->has('ClassName') does not affects performance and wherein provides honest reliable answer ensuring that object can be retrieved. |
I'll try to make my suggestion more explicit: Create a class I understand you're puzzled, and question the usefulness of So the only concern for the developer is to provide a working configuration to the container that is able to create any objects that have a lifetime of the incoming request itself, i.e. objects knowing how to process the request (controllers), how to validate parameters, how to query a backend database or other services. Explicitly not part of that is objects that represent some or all values of a specific request itself, that might be only created on the fly once processing of the request itself has already started. And that means the configuration of the DI container is considered "fixed": It does not change at runtime, so the only useful method that MUST always deliver working objects is Your second question: There is no difference for these two cases. You are always requesting something identified by a string from the container. Any The checks required for both cases are the same. No difference in performance when it comes to identifying whether or not PHP-DI can instantiate this class. Just imagine two scenarios: a) rely on autowiring and b) have an explicit entry with some The autowired class might need classes that cannot be instantiated by themselves, or it requires some scalar parameters that do not provide a hint what to insert by themselves. And even if the scalar parameter for this class would be declared, any class it depends on might suffer the same problem, so without actively recursing the entire class tree it is impossible to really know for sure. The explicitly defined class might also fail. It is impossible to know without executing the factory code itself, and this may try to pull more dependencies from the container that might fail, be it scalars or classes. It is basically the same situation with more explicit code. PHP-DI cannot know for sure if it is eventually able to instantiate something. Having successfully been able in the past (i.e. having an entry in the Note that the same problem might exist for any other container implementation that is relying on explicit configuration for every entry: It still might fail trying to instantiate something just because of a bug in the code that is trying to do it. Knowing a definition exists for something does not prove the defintion is able to provide whatever is expected. So in your case, it would actually solve the problem because no configured entry means you'll create one yourself, but in general the assumption that |
Hello!
php-di/php-di 6.4.0
Ubuntu 20.04
PHP 8.1
This result is true and this claims that an object with id 'Gt\PaymentToDriver\TopAccount' is in container:
\dd(TopAccount::class); gets:
But if you inspect container object in scope of same class's method, there is no object with id "Gt\PaymentToDriver\TopAccount"
\dd($this->container);
As result of this false positive, when I try get this item
I got unexpected exception, instead of the object kept in container:
So, my conclusion is:
$container->has(TopAccount::class) or the same: $container->has('Gt\PaymentToDriver\TopAccount'), returns false positive result.
Maybe there is some other method to ensure that there are no "Gt\PaymentToDriver\TopAccount" item in container?
The text was updated successfully, but these errors were encountered: