[12.x] Introduce #[Bind] attribute #56383
Merged
Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
Similar to #56334, now a developer can bind a specific concrete implementation to an interface via an attribute.
In the above scenario, if the environment is staging or production, then calling
app(ChatServiceInterface::class)will returnTwChatService. For all other environments (eg: dev or testing),FakeTwChatServicewould be returned.Why?
Our biggest use of interfaces is to provide a production version of the code, and then inside of tests, we swap out with a test implementation. All of our code type-hints the interface, but in order to figure out which concrete implementation it is, we have to jump back to the service provider to see where it's bound. This keeps it tidy and in one place.
Technical Decisions
We are keeping a cache of class strings which we have already checked for the
Bindattribute. This cuts down on repeated reflection if we already know the class does not have the attribute. While it will increase the memory footprint of the Container class slightly, it should improve performance on repeated instantiation of objects. Maybe this should be a static property instead? 🤔If using the container outside of the Laravel Application, then you must manually set the environment resolver. If none is set, then the attributes will be ignored.
Wildcards
We are using fuzzy-matching (via the
Str::is()method). If all environments are passed, then we will still compare all of the attributes to see if there is a more specific match.For the above,
app(MyInterface::class)will returnMyProdClassif the environment is production, butMyDummyClassfor all other environments.Improvements
The scoped/singleton property could possibly be shoe-horned in here.