Okay, I admit: I love php. People apparently don’t like hate it but I kinda grew up with that language.
I just watched The Social Network http://t.co/kzMW1ch6EF No wonder Facebook is awful, he did it all in PHP & Emacs.
— I Am Devloper (@iamdevloper) January 4, 2015
Let’s see what we can do for a change. The recent versions of php gained some beautiful features as well as some syntactic sugar. Let’s build a slim framework, that allows any kind of server application to be fragmented into modules. In this part we will look into how we want our modules to look and feel. Here are some design goals:
- modularity
- dependency injection
- event based
Note: This code requires at least php 5.4.
Each module is a standard php class. A singleton of that class is kept inside the main module loader. The module loader is also the factory for all modules. Everything is sitting nicely inside folders using and is included using a PSR-0 autoloader. Every time a module depends on another module the module loader kicks in and sees if that module instance already exists. If not it init()
-ializes it. Either way, the module will be there – ready to use. That process is called dependency injection. To define dependencies we will just have the required modules names as parameters.
Let’s not worry how the module loader would handle dependency injection for now. But what are we going to do if we need parameters for that function? Yes you guessed right: Returning a function!
By returning a function we have the ability to sneak variables into it via the use
keyword. Let’s take this one more step further before we dig into the module loader.
Our module system is supposed to be event based. Here is our convention for events. If an event is triggered the module loader finds all registered modules, that respond to that type of event. A module responds to an event type if it implements an on<EventType>()
-method. There is one problem though. Some modules need to do work before other can.
Example: Two modules are registered for the request
-event. Authentication and FileSystem. Authentication checks if we are allowed to do what we want to do. FileSystem simply responds with the requested file. Neither of those modules knows what the other one does. Authentication can opt out of the chain simply be throwing an Exception. But what if for some reason the module loader choose to execute FileSystems event handler first?
Event handlers need to be prioritized. And again you guessed correctly: We return an object that has a function and a priority build in. What else?
This is a way simplified implementation of what I currently use inside my Authentication module. (object)[]
cast the returned array into an stdClass object. This is simply for looks. The the value of that objects link parameter is a function. And it is the same old function we already used earlier. The priority parameter holds a number. The way this syntax looks made me call the returned object “link object”.
The module loader will execute all available event handlers for all registered modules. It’ll then sort the link objects by priority. Higher priority will execute first. (At the moment no-priority defaults to 100, but I guess this is to be discussed.) Then all link functions are executed in order.
Here is a complete module before we discuss how the module loader works internally in the next post. (Notice: calm is the name of my current application.)
Pew. The init()
method is executed as soon as the module is first loaded. It is used because __construct()
always returns $this
. For dependency injection to work, we need to be able to return our link object. Therefore this additional step is necessary to set up stuff that requires stuff from other modules. Yay!
Part 2 will cover the internal workings of the module loader.