Skip to content
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

Intercep class loading without Container #560

Closed
odahcam opened this issue Dec 4, 2017 · 12 comments
Closed

Intercep class loading without Container #560

odahcam opened this issue Dec 4, 2017 · 12 comments
Labels

Comments

@odahcam
Copy link
Contributor

odahcam commented Dec 4, 2017

It's too much unusual to have to use a $container var to load every class. I think there's could be a way to use the DI functionality without having to rewrite the entire application to load classes through a $container, maybe Composer's autoload could be intercepted or something else.

@mnapoli
Copy link
Member

mnapoli commented Dec 4, 2017

Hi, I think you may be confusing class loading (i.e. autoloading, what Composer does) and object instantiations (new SomeClass).

PHP-DI instantiates classes, but it does do any autoloading.

What you may have in mind is some kind of "overriding" of new SomeClass to inject dependencies in the constructor? That sounds a bit complicated, and magic, and to be honest out of the scope of a DI container, so this will not be added in this package.

I know migrating an existing legacy application to these kinds of patterns is not easy. There are some things that could help, for example if you are using the singleton pattern: change the getInstance() to use $container->get() instead of new. Anyway this is a very large topic, if you have a specific example please feel free to continue the discussion here and explain it, however I'll be closing the issue for now.

@mnapoli mnapoli closed this as completed Dec 4, 2017
@odahcam
Copy link
Contributor Author

odahcam commented Dec 4, 2017

Well, in other languages I worked with, this was the default behavior. It's very painfull to have to pass a $container trought all the application, so I wanna make some special configuration to set this up.

I think that PHP-DI receives some qualifyied class name and then (after some reflection stuff) instantiates it with some parameters, letting the loading job with Composer, right?

@mnapoli
Copy link
Member

mnapoli commented Dec 4, 2017

Again you are confusing class loading and object instantiation, those are very different things.

Also you should not pass the $container everywhere, instead you should call $container->get() at the root of your application (e.g. your router or dispatcher). Then you should use classic dependency injection in all your classes (so you should not have either new SomeClass or $container-get() in your code).

You can read http://php-di.org/doc/best-practices.html to learn more.

@mnapoli mnapoli added the support label Dec 4, 2017
@odahcam
Copy link
Contributor Author

odahcam commented Dec 4, 2017

I know what an loading class/function does (I've made a lot of them before using Composer), I know what is instantiation and you didn't answer my simple question.

Also the docs doesn't have any complete example from setting the container up to instantiating a class where something will be injected by PHP-DI (yes, I already read the best practices section). I can't figure out how it works, cause there's isn't a universal pattern for using some DI package, from what I read here I understand that I have to simple write $container->get() in my application boot and every instantiation I made will be intercepted by PHP-DI, I just keep getting more confused. 😕

@mnapoli
Copy link
Member

mnapoli commented Dec 4, 2017

Also the docs doesn't have any complete example from setting the container up to instantiating a class where something will be injected by PHP-DI

Well there is the Getting started guide which does just that, does it help? (especially the section Create the objects) If not, let me know precisely what is not clear to you.

from what I read here I understand that I have to simple write $container->get() in my application boot and every instantiation I made will be intercepted by PHP-DI

Yes that's it. Read the getting started guide, especially this section for more details: http://php-di.org/doc/getting-started.html#framework-integration

you didn't answer my simple question.

What is your question exactly? If this is this:

I think that PHP-DI receives some qualifyied class name and then (after some reflection stuff) instantiates it with some parameters, letting the loading job with Composer, right?

Then yes, the answer is yes: composer will include the file, PHP-DI will create the instance. Let's try not to use the word load here maybe that will be easier to discuss: files are included by Composer and instances are created by PHP-DI, that's it. And those are very different jobs.

@odahcam
Copy link
Contributor Author

odahcam commented Dec 4, 2017

Then yes, the answer is yes: composer will include the file, PHP-DI will create the instance. Let's try not to use the word load here maybe that will be easier to discuss: files are included by Composer and instances are created by PHP-DI, that's it. And those are very different jobs.

Nice, thanks. 😄

If you want to use PHP-DI with another framework or your own code, try to use $container->get() in you root application class or front controller.

Have no idea how the hell I could miss this. I'll test this functionallity tonight, thanks for the help.

Let's try not to use the word load here maybe that will be easier to discuss: files are included by Composer and instances are created by PHP-DI, that's it.

Ok.


I have two use cases, one with Slim + Pimple (which I want to remove) and one with native PHP code, both in PHP 7.1.

@mnapoli
Copy link
Member

mnapoli commented Dec 4, 2017

OK regarding Slim it should be easier with the bridge: http://php-di.org/doc/frameworks/slim.html

For transitioning from Pimple to PHP-DI you can take the closures you defined in Pimple and simply put them in PHP-DI like this: http://php-di.org/doc/php-definitions.html#factories

@odahcam
Copy link
Contributor Author

odahcam commented Dec 4, 2017

I've done the Slim integration before, but I reverted everything, because I made my entire project dependent from Slim and I don't want that. I'm trying to implement PHP-DI in a native way so then my Slim router can just use PHP-DI as a plus provided by my application scenario. Because of that, the Slim integration will take longer to work for me. Thanks for the usefull links.

@SvenRtbg
Copy link
Contributor

SvenRtbg commented Dec 4, 2017

I'd like to add that usually frameworks that allow DI containers, and Slim in particular, use that container in two distinct places to fetch objects from it: First in order to get all necessary objects to bootstrap processing an incoming request in general (which would for example create the PSR-7 request and response objects, the router, etc.), and the second part takes place if the requested controller has been identified.

If you feel the need to pass the container through multiple objects in order to fetch something deeper inside:

  1. Identify what you have to fetch from the container in an object.
  2. Make it a parameter in the constructor instead.
  3. Write a definition for the DI container if you have to (hint: autowiring in PHP-DI may resolve the object automatically), to pass the dependency into the constructor.
  4. See if the object now can be resolved by the DI container - and then move up on the chain to the next object that passes the container through, and start over.

It'll take some experience to fully grasp the concept, but with Slim you basically only have to pass the DI container into the App object and provide it with the configuration to build all objects your application needs. Slim itself requires the DI container to emit some specific objects when asking for "generic" keys like "request", but the Slim bridge will correctly cover exactly this for PHP-DI.

@odahcam
Copy link
Contributor Author

odahcam commented Dec 4, 2017

Well, I tryied to use the empty container get ($container->get();) and it didn't work:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function DI\Container::get(), 0 passed

@mnapoli
Copy link
Member

mnapoli commented Dec 5, 2017

I did not mean literally calling $container->get(), you have to ask for something (e.g. a controller, a service, etc.).

You should really use a framework integration first I think, that will be easier to get started.

@odahcam
Copy link
Contributor Author

odahcam commented Aug 11, 2021

Funny how this is confusing for beginners to understand IoC concepts when the only thing you know is some framework that magically "just works". I hope my lack of knowledge helps someone through this thread and, if you need any help understanding IoC, please ping me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants