I'm building a MVC PHP framework and I wonder which are the best practices to load what I need in my classes, be it other classes or plain configuration.
Till today I've used singletons, registry and lately a dependency injection container.
While many people claim that DI is the way to go, it seems to me like it justs moves the problem of coupling between components into another place.
Singletons introduce global state, registry introduces tight coupling and DI introduces... well, lots of complexity. I am still confused and can't find a proper way to wire my classes each other.
In the meanwhile, I came up with a custom solution. Actually it's not a solution, it just abstracts the implementation of service loading from my code.
I built an abstract class with _load_service and _load_config methods which all the components of my framework extend in order to load other services or configuration.
abstract class Base_Component {
function _load_service($service) {
// could be either
return DI_container::getInstance()->$service;
// or
$class = '\services\\'.$service;
return new $class;
// or other implementation
}
}
The implementation of loading them is now implemented in only one place, the base class, so at least I got rid of code lines like the following into my components:
$database = new Database(Registry::getInstance()->load('db_config'));
or
$database = DI_container::getInstance()->database;
Now if want a database instance I do this
$database = $this->_load_service('database');
and the implementation of service loader, container, registry or whatever can be easily changed in a single class method without having to search through all my code to change calls to whatever container implementation I was using before.
But as I said I'm not even close to sure about what method I will use for loading classes and configuration.
What are your opinions?
Why reinvent the wheel? Use Pimple as your DI container, and learn how to use it from its documentation.
Or, use Silex microframework as a base to create your own framework. It extends Pimple functionality, so you can use dependency injection.
To answer your question, this is how you use a DI without coupling your classes to it:
interface ContainerInterface {
public function getService($service_name);
public function registerService($service_name,Closure $service_definition);
}
class Application {
public function __construct(ContainerInterface $container) {
$this->container= $container;
}
public function run() {
// very simple to use!
$this->container->getService('db')->someDatabaseQuery();
}
}
$c = new My_DI_Container;
// Service definitions could be in a separate file
$c->registerService('db',function() { return new Database('some config'); });
// Then you inject your DI container into the objects that need it
$app = new Application($c);
$app->run(); // or whatever
This way, the DI container is decoupled and in the future you could use a different implementation. The only requirement is that it implements the ContainerInterface.
Note that the container object is being pushed, and not pulled. Avoid using singleton. To get/set single-instance objects, use the container (that's its responsibility). And to get the container instance, just push it through constructors.
Answer to your question; Look at PHP autoloading. Registering classes via autoloading makes it so you don't have to put require/includes everywhere, which really has a positive impact on RAD (rapid application development).
My thoughts:
Kudos for attempting such a daunting task, your approach appears to based on good practices such as singletons and factories.
I don't care for dependency injection. OOP is based on encapsulation, injecting one object into another, imo, breaks that encapsulation. When you inject an object into another object, the target object has to 'trust' that nothing regarding the injected object has changed, otherwise you may get unusual behavior.
Consider name-spacing your classes (not PHP name-spacing, but prefix your framework like Zend does, Zend_), this will help so you can register a namespace, then when a class is called the autoloader will ensure that the proper class is loaded. This is how Zend_Framework works. For specifics check out Zend_Loader_Autoloader. The Symfony framework actually takes this one step further; during the first request it will go through all known locations looking for class files, it will then build out an array of the classes and paths to the files then save the array to a file (file caching), so subsequent requests won't have the same overhead. Something to consider for your framework.
As far as config files go, Symfony uses YAML files, which I have found to be extremely flexible. You can even include PHP code for increased flexibility. Symfony has provided a stand-alone YAML parser that is easy to use. You can increase performance by adding a caching layer and caching parsed YAML files so you don't have to parse the files for every request.
I am assuming you are building your framework on top of an ORM. My recommendation would be not to any functionality specific to a version of the ORM, otherwise your framework becomes coupled with that version and you will have to upgrade both the ORM and the framework at the same time.
I would suggest looking under the hood at other frameworks and see if you can pick the best of each; resulting in a solid, easy to use framework.
Related
We have some legacy laravel projects which use facades in the classes.
use Cache;
LegacyClass
{
public function cacheFunctionOne()
{
$result = Cache::someFunction('parameter');
// logic to manipulate result
return $result;
}
public function cacheFunctionTwo()
{
$result = Cache::someFunction('parameter');
// different logic to manipulate result
return $result;
}
}
Our more recent projects use dependency injection of the underlying laravel classes that the facades represent as has been hinted at by Taylor Otwell himself. (We use constructor injection for each class, but to keep the example short, here I use method injection and use a single class.)
use Illuminate\Cache\Repository as Cache;
ModernClass
{
public function cacheFunctionOne(Cache $cache)
{
$result = $cache->someFunction('parameter');
// logic to manipulate result
return $result;
}
public function cacheFunctionTwo(Cache $cache)
{
$result = $cache->someFunction('parameter');
// different logic to manipulate result
return $result;
}
}
I know facades can be mocked
public function testExample()
{
Cache::shouldReceive('get')
->once()
->with('key')
->andReturn('value');
$this->visit('/users')->see('value');
}
Which works nicely for unit tests. The problem I am trying to understand is if these facades are mocked 'globally'.
For example, lets imagine I am writing an integration test (testing a few interconnected classes while mocking services - not an end to end test using live services) which at some point, executes two separate classes which contain the same facade that calls the same method with the same parameters.
In between these classes being called, is some complex functionality that changes what data is returned by that facades method using the same parameter.*
$modernClass->cacheFunctionOne($cache); // easily mocked
// logic that changes data returned by laravel Cache object function 'someFunction'
$modernClass->cacheFunctionTwo($cache); // easily mocked with a different mock
Our modern classes are easy to test because the underlying class that the facade represents is injected into each class (in this example, each method). This means I can create two separate mocks and inject them into each class (method) to mock the different results.
$legacyClass->cacheFunctionOne();
// logic that changes data returned by laravel Cache object function 'someFunction'
$legacyClass->cacheFunctionTwo();
In the legacy systems though, it would seem that the mocked facade is 'global' so that when the facade is run in each class, the exact same value is returned.
Am I correct in thinking this?
*I understand this example may seem completely redundant from a code architecture and testing point of view, but I am stripping out all real functionality to try and give some sort of 'simple' example of what I am asking.
Dependency Injection vs Facades
One of the major benefits of Dependency Injection is that code becomes a lot more testable once you start injecting dependencies into methods instead of instantiating/hardcoding them inside the method. This is because you can pass in the dependencies from inside unit tests and they will propagate through the code.
See: http://slashnode.com/dependency-injection/
Dependency Injection stands in stark contrast to Facades. Facades are static global classes, the PHP language does not allow one to overwrite or replace static functions on static classes. The Laravel facades use Mockery to provide mock functionality and they are limited by the same facts as above.
The issue for integration testing can come where you are hoping to retrieve data from a non-mocked Cache but once you use Facade::shouldReceive() then Facade::get() will be overridden by the mocked Cache. The reverse is also true. As a result, Facades are inappropriate where you are interleaving calls for mocked and unmocked data.
In order to test your code with the different data sets that you require, the best practice would be to refactor your legacy code to use DI.
Integration Tests
Easier method
An alternative is to call multiple Facade::shouldReceive() with expectations at the beginning of your integration test. Ensuring that you have the right numbers of expectations in the right order for each of the calls you will make in the integration test. This would probably be the faster way to write tests given your existing codebase.
Harder method
Whilst dependency injection is programming best practice. It could very well be that your codebase has so many legacy classes that it would take an unbelievable amount of time to refactor. In this case, it might be worthwhile considering end-to-end integration tests using a test database with fixtures.
Appendix:
For how mockery is called by Facade see - function createMockByName(): https://github.com/laravel/framework/blob/5.3/src/Illuminate/Support/Facades/Facade.php
For examples on chaining mockery calls see fhinkel commented on Feb 6, 2015: https://github.com/padraic/mockery/issues/401
I'm making my own primitive MVC framework with PHP, and I'm wondering where I should load/instantiate corresponding controller dependencies?
In the constructor of each controller (tightly coupled) or inject them (loosely coupled)?
The only part of the latter that I'm not too sure of is for the dependencies to be instantiated on bootstrap level, outside of the MVC paradigm, before being injected. Not every controller uses the exact same dependencies besides the default parent ones. I would have to instantiate them all, which would also create a lot of overhead.
I've seen some existing frameworks do it like $this->load->model('model'); // CodeIgniter in the constructor, but I have no clue on why they're doing it like that.
I would suggest you inject the dependencies, so your controllers are less coupled to your framework. This will make a switch to another framework easier.
About instantiating dependencies: I suggest you use (or implement) a dependency injection container. This container should contain factories that can instantiate services.
In an ideal situation your controllers are services too (meaning they too have factories in the dependency injection container).
This way only the controller you need for a particular request will be instantiated, and therefor only its dependencies are instantiated.
When building you own framework, this means that after the routing phase (when the correct controller is known), the framework should grab that controller from the container. The container itself will make sure all dependencies that are needed will be provided.
Have a look at Pimple for an example of a simple dependency injection container.
PS: That line from CodeIgniter looks a lot like the service locator pattern. This pattern is similar to dependency injection, but does not provide full inversion of control.
Q: Where should i load/instantiate corresponding controller dependencies?
There are multiple ways.
The load and instantiation concepts are basically "before/outside" and "after/inside".
Before and outside means, that you load the file containing a class (which you want to instantiate and pass to the controller), before you load the controller.
But how do you know, what the controller needs, before loading the controller? Uh..
Dependency Description Files
A description file comes into play, describing the wiring between your controller and it's dependencies. In other words, you can see the dependencies of your controller by looking at it's dependency description file. This concept is often used by Dependency Injection tools, which analyze the object and pull the dependencies names out automatically. It's also possible to maintain such a wiring configuration file manually. But it's tedious.
Service Locator
A Service Locator is a instantiation helper for dependencies.
Basically, it contains the same information like a dependency description file, but this time in form of a registry. The link between parts of your application becomes this registry.
Both strategies introduce overhead. It's a trade-off. When you change the perspective and look at things from an application with maybe 500+ classes, then you realize that a dependency injection tool is sometimes worth it.
Manual Injection
via Constructor Injection.
After and inside means, that you load the file containing your controller and then start to care about the dependencies.
At this point the class is not instantiated, yet, but the autoloader might do it's dirty deeds behind the scene. He evaluates the use statements at the top of your controller file. The use statements declare namespaced classes, which the autoloader resolves to actuall files and loads them. You might then start to use these classes as dependencies in your controller. This is probably the easiest way to solve your problem and i strongly suggest looking into the topics autoloading with namespaces and use-statements.
When the class is instantiated, you have the following possiblities:
use might use Setter Injection or Reference Injection to set the dependencies to the object. This requires that your Constructor Dependencies are already solved or your constructor is empty.
It's possible to combine these strategies.
Q: What does this do $this->load->model('model'); // CodeIgniter?
CodeIgniter is a legacy application framework. It was created in times, when namespaced autoloading wasn't available. $this->load is a basic class loading helper. This is the opposite of an "auto"loader, (which surprise, surprise) loads things automatically.
CodeIgniters loader class is used to load various other classes, like libraries or files from the view, helpers, models or user defined stuff. This is again the concept of a registry. Here the registry just knowns where things are in your application layout and resolves them. So $this->load->model('model'); means that the modelfunction must have some piecies of information, about the position of model files in your application.
You provide a model name and the path for the file is constructed by model.
And this is exaclty what it does (except a bit of overhead): https://github.com/EllisLab/CodeIgniter/blob/develop/system/core/Loader.php#L223.
Since I'm a Symfony developer, I can only give you a reference to Symfony.
I think you should do like they are doing in Symfony by thinking about what you need in each
Controller object.
At least, you need :
a Request object
and a Model loader object that gives you every Model you need.
Create a BaseController that implements these few functions and then extend it with custom Controllers.
You can also take a look on Silex : http://silex.sensiolabs.org/ a Micro Framework
Hope it helps.
When do you say "In the constructor" you mean to pass in the conatiner and pull the dependencies from them (in the constructor)?
<?php
class SomeController
{
public function __construct($container)
{
$this->service1 = $contanier->get('service1);
}
//...
}
I advice against that, though simpler and easier you will be coupling your controllers to the container thus using a ServiceLocator instead of truly inversion of control.
If you want your controllers to be easy unit-testable you should use inversion of control:
class SomeController
{
public function __construct($service1)
{
$this->service1 = $service1;
}
//...
}
And you can even create your controller as a service inside the container:
// this uses Pimple notation, I hope you get the point
$container['controller'] = function($c) {
return SomeController($c['service1']);
}
Use proxy services to lazy load them
Also if your controllers needs more than some services and you won't be using all of them you can:
1) Use proxy services in order to lazy load the service only when they are really needed
<?php
class ProxyService
{
/**
* #var Service1Type
*/
private $actualService;
public function __construct()
{
$this->actualService = null;
}
private function initialize()
{
$this->actualService = new Service1(); // This operation may take some time thus we deferred as long as possible
}
private function isInitialized()
{
return $this->actualService === null;
}
public function someActionOnThisService()
{
if (!$this->isInitalized()) {
$this->initalize();
}
$this->actualService->someActionOnThisService();
}
There you have a simple proxy object with lazy loading. You may want to check the fantastic Proxy Manager Library if you want to go that route
2) Split your controller
If your contoller has too many dependencies, you may want to split it.
In fact you may want to read the proposal by Paul M. Jones (lead developer of Aura Framework) about MVC-Refinement, IMHO is a good read even though you may not fully agree with it.
Even if you split your controller in order to reduce the dependencies, lazy loading your dependencies is a good idea (obviously you'll have to check weather if its doable in your context: more work in order to gain more speed).
Maybe you need to define __autoload() function before you try to load the Classes which is not loaded yet. Like:
function __autoload($className) {
require "/path/to/the/class/file/$className.php";
}
My example is very very simple to auto require the file which the class definition is in.
You can also use if-else statement or switch statement in that function to fit your own situations smartly.
The __autoload() function is called when PHP doesn't find the class definition, works for new, class_exists(), call_user_method(), etc, and absolutely for your dependences/parents classes. If there is still no class definition after __autoload() is called, PHP will generate an error.
Or you can use spl_autoload_register() function instead of __autoload() more gracefully.
For more information, you might want to see:
http://php.net/manual/en/function.autoload.php
http://php.net/manual/en/function.spl-autoload-register.php
First of all, sorry for my bad English, I hope you understand what I'm saying.
Here is my problem:
Lets assume i have an MVC application including standard router, controller, model(service) layer and some kind of db connector.
Model layer depends on a db connector, controllers depends on models/services and the top-level "application" class depends on routers and controllers.
My object hierarchy looks like this:
App -> ControllerFactory -> ServiceFactory -> DAO -> DbConnection
Perhaps, written above doesn't look like best application architecture ever, but i want to focus on the other thing:
When i'm trying to instantiate an App class i should pass all dependencies to the class instantiated; class dependencies, in turn, has their own dependencies and so on.
As a result I get all hierarchy stack instantiated at once. But what if i dont need to access the database in some cases; what if some controllers are used for rendering static templates without model interaction?
I mean, what if there are some special cases when class does not require its own dependencies(and in some cases it does)? Should i inject dependencies conditionaly or something?
I'm really stuck at this point and i don't know what to do.
Update: after re-reading carefully your question, here is another advice: yes, every class has different dependencies.
Don't inject every object into every other object. For example, some services might need DAOs, so inject them. But if a service doesn't need a DAO, don't inject any DAO.
The rest of my answer is valid if you have (for example) a service that needs a DAO (and thus a DB connection) not for every method.
What you may be looking for is lazy injection.
It is the act of injecting a dependency not loaded, so that the object is loaded only if/when used.
In conrete terms, that means injecting a proxy object, that would look like and behave exactly like the original object (for example, the db connection).
Several DI container (frameworks) support this so you don't have to create proxies yourself. I'll take as an example PHP-DI (I work on that project FYI).
Here is an example using annotations:
use DI\Annotation\Inject;
class Example {
/**
* #Inject(lazy=true)
* #var My\Class
*/
protected $property;
/**
* #Inject({ "param1" = {"lazy"=true} })
*/
public function method(My\Class $param1) {
}
}
Of course if you don't want to use annotations you can use any other configuration you want (PHP, YAML, …). Here is the same example by configuring the container in pure PHP:
$container->set('Example')
->withProperty('property', 'My\Class', true)
->withMethod('method', array('param1' => array(
'name' => 'My\Class',
'lazy' => true,
)));
See more in the documentation about Lazy Injection.
Note: you may not be using a Container for now (and that's not a problem), but for tackling lazy injection this is a fair amount of work and you might need to start considering using one.
If your dependency construction is complex, simply add a new factory class that should contain all the logic to create a correct object for you.
class AppFactory(){
__construct(all params){
}
build(useDB=true){
// logic to build
if(useDB){
App = new App(new ControllerFactory(new ServiceFactory(new DAO(new DbConnection(params)))))
} else {
App = new App(new ControllerFactory(new ServiceFactory(null))))
}
return App;
}
}
I'm building a small framework that I can use for repeated mundane stuff on future small projects.
I'm stuck on the best way to access libraries from inside a controller. I originally implemented a system similar to CodeIgniter's whereby my main controller class is basically a super object and loads all the classes into class variables which are then accessed by extending the controller and doing like $this->class->method()
I find that a little ugly, though. So I thought of just loading each class individually on a per-use basis in each controller method.
What's the best (cleanest) way of doing this?
To only ever have one instance of each class, you could create a simple service container.
class ServiceContainer
{
protected $services;
public function get($className)
{
if (!array_key_exists($className, $this->services)) {
$this->services[$className] = new $className;
}
return $this->services[$className]
}
}
Then create one ServiceContainer instance per application. Inject the container into all of your controllers and use
public function someAction()
{
$this->container->get('Mailer')->send($email_data);
}
Simple example, and obviously needs a lot of work to make useable (for instance autoloading needed and handling of file paths for ease of use, or easier way to add services without getting them, etc).
I dont like the way CodeIgniter does it. Its never seemed right to me. I favor an auto loading class pushed onto the spl_autoload stack. And then just calling the class as normal like:
$class = new SomeClass();
PHP provides autoload functionality with SPL and spl_autoload (and related functions). You can register a custom autoloader for your library code.
For the shared functionality handled by your application, have you considered the Front Controller design pattern?
I'm building out a small project to try to teach myself as much of the fundamentals as possible, which for me means not using a prefabricated framework (As Jeff once put it, "Don't reinvent the wheel, unless you plan on learning more about wheels" [emphasis mine]) and following the principles of Test Driven Development.
In my quest, I recently ran into the concept of Dependency Injection, which appears essential to TDD. My problem is that I can't quite wrap my head around it. My understanding so far is that it more or less amounts to "have the caller pass the class/method any other classes it may need, rather than letting them create them themselves."
I have two example issues that I'm trying to resolve with DI. Am I on the right track with these refactorings?
Database Connection
I'm planning to just use a singleton to handle the database, as I'm currently not expecting to use multiple databases. Initially, my models were going to look something like this:
class Post {
private $id;
private $body;
public static function getPostById($id) {
$db = Database::getDB();
$db->query("SELECT...");
//etc.
return new Post($id, $body);
}
public function edit($newBody) {
$db = Database::getDB();
$db->query("UPDATE...");
//etc.
}
}
With DI, I think it would look more like this:
class Post {
private $db; // new member
private $id;
private $body;
public static function getPostById($id, $db) { // new parameter
$db->query("SELECT..."); // uses parameter
//etc.
return new Post($db, $id, $body);
}
public function edit($id, $newBody) {
$this->db->query("UPDATE..."); // uses member
//etc.
}
}
I can still use the singleton, with credentials specified in the application setup, but I just have to pass it from the controller (controllers being un-unit-testable anyway):
Post::getPostById(123, Database::getDB);
Models calling models
Take, for example, a post which has a view count. Since the logic to determine if a view is new isn't specific to the Post object, it was just going to be a static method on its own object. The Post object would then call it:
class Post {
//...
public function addView() {
if (PageView::registerView("post", $this->id) {
$db = Database::getDB();
$db->query("UPDATE..");
$this->viewCount++;
}
}
With DI, I think it looks more like this:
class Post {
private $db;
//...
public function addView($viewRegistry) {
if ($viewRegistry->registerView("post", $this->id, $this->db) {
$this->db->query("UPDATE..");
$this->viewCount++;
}
}
This changes the call from the controller to this:
$post->addView(new PageView());
Which means instantiating a new instance of a class that only has static methods, which smells bad to me (and I think is impossible in some languages, but doable here because PHP doesn't allow classes themselves to be static).
In this case we're only going one level deep, so having the controller instantiate everything seems workable (although the PageView class is getting its DB connection indirectly by way of the Post's member variable), but it seems like it could get unwieldy if you had to call a method that needed a class that needed the class that needed a class. I suppose that could just mean that's a code smell too though.
Am I on the right track with this, or have I completely misunderstood DI? Any criticisms and suggestions are greatly appreciated.
Yes. It looks like you have the right idea. You'll see that as you implement DI all your dependencies will float to the "top". Having everything at the top will make it easy to mock the necessary objects for testing.
Having a class that needs a class that needs a class is not a bad thing. What your describing there is your object graph. This is normal for DI. Lets take a House object as an example. It has a dependency on a Kitchen; the Kitchen has a dependency on a Sink; the Sink has a dependency on a Faucet and so on. The House's instantiation would look something like new House(new Kitchen(new Sink(new Faucet()))). This helps to enforce the Single Responsibility Principle. (As an aside you should do this instantiation work in something like a factory or builder to further enforce the Single Responsibility Principle.)
Misko Hevery has written extensively about DI. His blog is a great resource. He's also pointed out some of the common flaws (constructor does real work, digging into collaborators, brittle global state and singletons, and class does too much) with warning signs to spot them and ways to fix them. It's worth checking out sometime.
Dependency injection is about injecting. You need some solution to inject the external object.
The traditional approaches are:
constructor injection __construnctor($dependecy) {$this->_object = $dependency}
setter injection setObject($dependency) {$this->_object = $dependency}
gettter injection getObject() {return $this->_dependency} and oveloading this method eg. from stub or mock in the tests.
You may also mix all the above, depends what you need.
Avoid static calls. My personal rule is use static only when you call some functions, e.g. My::strpos() or when dealing with singletons or registry (which should be limited to minimum, because global state is evil).
You will rarely need static methods when your app has a good dependency container.
Take a look at the other dependency injection + [php] topics on SO.
Edit after comment:
The container
Different frameworks handle the container in different way. Generally this is an object, which holds the instances of objects you need, so you don't have to instantiate new object each time. You may register any object with such a container, and then access it anytime you need.
The container may instantiate all the resources you need at boot time, or lazy load the resource when accessed (better solution).
As an example, consider:
Zend Application Resource Plugins
Symfony Dependency Injection Container
Another great reference:
http://martinfowler.com/articles/injection.html
It's certainly going into the right direction but you should not stop there.
The point of DI is to remove strong couplings between classes to allow for easier substitution of single components. This will allow for better testability because you can substitute dependencies more easily with Mocks and Stubs. And once your code is tested, it is much easiert to change and maintain.
Consequently, you should also remove those other aspects in your code that create strong coupling smells as well, e.g. remove the static methods and the singleton and any other globals.
For some more information on that, please see
How is testing the registry pattern or singleton hard in PHP?
http://gooh.posterous.com/singletons-in-php
http://kore-nordmann.de/blog/0103_static_considered_harmful.html
http://fabien.potencier.org/article/11/what-is-dependency-injection
EDIT: with a couple of others answers suggesting to use a DI container, I feel it's necessary to stress that you do not need a DI container to do DI. The second blog post in the last link given above discusses this.
To answer your questions: yes, you are on the right track. To give you more details: this is one of the best posts I found related to DI:
http://www.potstuck.com/2009/01/08/php-dependency-injection
You will understand what a container is:
$book = Container::makeBook();
Regarding the second example: in your method addView I would try to avoid passing the object $viewRegistry, I would check the condition outside in the controller.