I finally had that 'eureka' moment with respect to the Slim 4, PHP-DI and autowiring.
After roughing out the controllers for Mabel I realized I had a small problem in that the api didn't return a 404 response when a uri was sent that didn't exist.
Like, if the client asked for /foo/bar the api would return a 200 OK response. That's all sorts of wrong.
So I started to dig into the documentation a bit trying to figure out how to implement the correct behavior. As part of my research into that, I ran across the following blog post on error handling in Slim 4.
That post contained a link to the slim-skeleton github repository, which I found pretty intriguing. In particular I really liked how it manages dependencies and routes. Up until now I'd put all the code loading up the container straight into docroot/index.php, but I've never liked that. Seeing an alternative approach that I did like, I just copied it.
I also really liked how each endpoint corresponded to a separate class with a single action() method. I feel that writing unit tests will be more straightforward for code structured this way and I also like how the file structure of the project literally tells you where to find each method for each endpoint. So I copied that too.
I still wasn't fully understanding how the implementation worked though. Looking at the parent UserAction class wasn't much help. Looking at the parent Action class was, however, something of an eye opener. At some point Slim 4 must be executing the ListUsersAction class (or any other class that extends Action) as if it were a function. That was triggering the __invoke magic method, and when that happened the Request and Response objects and the request arguments were being passed in.
After I figured that out I assumed I'd go to app/routes.php and see where all the dependencies were being instantiated and passed to the constructors of the various action classes. Only that's not what was happening at all. Nothing was happening. The route was being defined and linked to a specific class that wasn't even instantiated.
It was as if . . . ohhhhhhhhhhhhhh.
Slim 4 is using reflection to determine whether a defined route is being linked to a closure, a class or the method of a class. It's then executing that closure, class or method as a callable and passing along the same three parameters every single time.
And if Slim 4 is doing that, it must also be using reflection to inspect the constructor of each class it's asked to instantiate and using the type hinting of the constructor parameters to search the container object for the corresponding closure that provides that type hinted class in its instantiated form.
So that's what auto-wiring is.
No comments:
Post a Comment