Dependency injection vs abstract class vs inheritance vs singleton - php

I have three classes:
a Logger that logs process information to a file
a Checker that validates input data
an Operations that does things on the input data.
I need Logger in both Checker and Operations to output (log) the process.
I need Checker in Operations, in order to check validity of data.
class Logger {
}
class Checker {
// inherit Logger ?
// dependency-inject Logger ?
// access Logger statically ?
// compose Logger as singleton or create new object ?
}
class Operations {
// inherit Logger ?
// dependency-inject Logger ?
// access Logger statically ?
// compose Logger as singleton or create new object ?
}
The application will create only one instance of Operations and Checker classes. The question is - in situations where no new objects are needed or created, what type of class should Logger be and how should it be implemented in the Operations and Checker classes?

If you are programming to interfaces, then the most flexible option is to use a decorator:
interface ILogger
{
function log($msg);
}
class FileLogger implements ILogger{
function log($msg)
{
file_put_contents('file.dat', $msg . "\n", FILE_APPEND);
}
}
interface IChecker
{
function check($var);
}
class Checker implements IChecker {
function check($var)
{
//do some checking
return true;
}
}
//decorator
class LoggingChecker implements IChecker
{
private $checker;
private $logger;
function __construct(IChecker $checker, ILogger $logger)
{
$this->checker = $checker;
$this->logger = $logger;
}
function check($var)
{
$checkResult = $this->checker->check($var);
$this->logger->log('check result is: ' . ($checkResult)? 'a success' : 'a failure');
return $checkResult;
}
}
interface IOperations
{
function doOperation($var);
}
class Operations implements IOperations{
private $checker;
function __construct(IChecker $checker)
{
$this->checker = $checker;
}
function doOperation($var)
{
if($this->checker->check($var)){
//do some operation
}
}
}
//composotion root
//create concrete logger, in this case a FileLogger instance, though you could latter create a SqlLogger or EmailLogger
//and swap it without any changes to the other classes
$logger = new FileLogger();
//create concreate checker
$checker = new Checker();
//create decorated checker
$loggingChecker = new LoggingChecker($checker, $logger);
//Operations can now be instantiated with either the regular checker, or the decorated logging checker, and it will
//work just the same, with no knowledge of the existense of loging, or indeed any knowledge of how the checker functions, beyond
//the fact it has a method called check that excepts a single parameter
$operation = new Operations($checker); //no logging is done
//OR
$operation = new Operations($loggingChecker); //logging is done
Note that i only created a decorator for IChecker in the above example for berevity.
You could also create a decorator for IOperations eg LoggingOperations that works in the same way - it depends on an instance of ILogger and IOperations.
You would instantiate it with the same concrete ILogger implementation ($logger) and IOperations implementation ($operation).
The class that uses this object would have a single dependancy on IOperations and could be instantiated with either $operation or $logginOperation and behave in the same way.
Hopefully this example gives you an idea of the flexibility of programming to interfaces and how the decorator pattern can simplify dependent classes and help enforce SRP

Answering directly to your question, what kind of class should logger be...
A classic example of a true singleton is a logging service. Suppose we
have an event-based logging service: Client objects request that text
be logged by sending a message to the logging service. Other objects
actually log the text somewhere (console, file, whatever) by listening
to the logging service for these logging requests and handling them.
First, notice that the logging service passes the classic test for
being a singleton:
The requesters need a well-known object to which to send requests to
log. This means a global point of access. Since the logging service is
a single event source to which multiple listeners can register, there
only needs to be one instance.
More info here Why we should consider the «Logger» class as a singleton?
For a nice logger, in case you dont have one at your framework, you should take a look of this one klogger

It depends , is there a possibility to have logger objects with different properties ? (e.g. to write the log into other folders or do something different with the message to be logged based on their properties) If so dependency injection is the way.
Does the logger perform the same way and doesn't even need properties ? (e.g. it just write the msg to a predefined file relative to the source folder). Than you don't even need to use singleton it could be a Utilities class with static methods.
And finally if your logger needs initialization and you initialize it only once then you could use singleton.

Related

Scalable way of implementing the Registry pattern in PHP?

I was wondering if there's a good way to implement the registry pattern in PHP, let me be more clear:
I do know that a Registry is used when you need to keep track of the object you instantiate in order to reuse them and not re-instantiate them again from script to script, e.g. I have a Database class that I want to instantiate only once and then use for all my scripts and I do not want to re-instantiate it again and again. Another example could be a User class that represents an instance of the currently logged in user. I could not use a Singleton in this case, cause e.g. I need another User instance for example when I want to retrieve a friend of the currently logged in user etc.
So I came up with the idea that the Registry better suits this kind of needs in such cases.
I also know that there are two ways of implementing it, or better two ways in order to access the stored instances:
Explicitly or externally, meaning that the Registry should be called every time you need to recover an instance inside your scripts or you need to put an instance inside of it;
Implicitly or internally, meaning that you make kind of an abstract class with a getInstance() method that returns an instance with the get_called_class() late static binding feature, adds it to the registry and then return that instance from the registry itself taking care that if a $label parameter is passed to the getInstance() method, then that particular instance from the registry will be returned. This approach is kinda transparent to the consumer and in my opinion is cleaner and neater (I'll show both implementations, though).
Let's take a basic Registry (really simple implementation, just an example took from a book):
class Registry {
static private $_store = array();
static public function set($object, $name = null)
{
// Use the class name if no name given, simulates singleton
$name = (!is_null($name)) ? $name: get_class($object);
$name = strtolower($name);
$return = null;
if (isset(self::$_store[$name])) {
// Store the old object for returning
$return = self::$_store[$name];
}
self::$_store[$name]= $object;
return $return;
}
static public function get($name)
{
if (!self::contains($name)) {
throw new Exception("Object does not exist in registry");
}
return self::$_store[$name];
}
static public function contains($name)
{
if (!isset(self::$_store[$name])) {
return false;
}
return true;
}
static public function remove($name)
{
if (self::contains($name)) {
unset(self::$_store[$name]);
}
}
}
I know, Registry could be a Singleton, so you never have two Registry at the same time (who needs them someone could think, but who knows).
Anyway the externally way of storing/accessing instances is like this:
$read = new DBReadConnection;
Registry::set($read);
$write = new DBWriteConnection;
Registry::set($write);
// To get the instances, anywhere in the code:
$read = Registry::get('DbReadConnection');
$write = Registry::get('DbWriteConnection');
And internally, inside the class (taken from the book) when getInstance is called:
abstract class DBConnection extends PDO {
static public function getInstance($name = null)
{
// Get the late-static-binding version of __CLASS__
$class = get_called_class();
// Allow passing in a name to get multiple instances
// If you do not pass a name, it functions as a singleton
$name = (!is_null($name)) ?: $class;
if (!Registry::contains($name)) {
$instance = new $class();
Registry::set($instance, $name);
}
return Registry::get($name);
}
}
class DBWriteConnection extends DBConnection {
public function __construct()
{
parent::__construct(APP_DB_WRITE_DSN, APP_DB_WRITE_USER, APP_DB_WRITE_PASSWORD);
} }
class DBReadConnection extends DBConnection {
public function __construct()
{
parent::__construct(APP_DB_READ_DSN, APP_DB_READ_USER,APP_DB_READ_PASSWORD);
}
}
Apparently referring to the registry indirectly (second case) seems more scalable for me, but what if some day I would need to change the registry and use another implementation, I would need to change that calls to Registry::get() and Registry::set() inside the getInstance() method in order to suit the changes or is there a smarter way?
Did someone of you came across this problem and found an easy way to interchange different registries depending on the type of application on the complexity etc.?
Should be a configuration class the solution? Or is there a smarter way to achieve a scalable registry pattern if it is possible?
Thanks for the attention! Hope for some help!
First of all. It's great that you spotted the problem of your approach by yourself. By using a registry you are tight coupling your classes to the registry where you pull your dependencies from. Not only that, but if your classes have to care about how they are stored in the registry and get grabbed from it (in your case every class would also implement a singleton), you also violate the Single-Responsibility-Principle.
As a rule of thumb keep in mind: Accessing objects globally from within a class from whatever storage will lead to tight coupling between the class and the storage.
Let's see what Martin Fowler has to say about this topic:
The key difference is that with a Service Locator every user of a service has a dependency to the locator. The locator can hide dependencies to other implementations, but you do need to see the locator. So the decision between locator and injector depends on whether that dependency is a problem.
and
With the service locator you have to search the source code for calls to the locator. Modern IDEs with a find references feature make this easier, but it's still not as easy as looking at the constructor or setting methods.
So you see it depends on what you are building. If you have a small app with a low amount of dependencies, to hell with it, go on with using a registry (But you absolutely should drop a classes behavior to store itself into or getting grabbed from the registry). If that's not the case and you are building complex services and want a clean and straightforward API define your dependencies explicitly by using Type Hints and Constructor Injection.
<?php
class DbConsumer {
protected $dbReadConnection;
protected $dbWriteConnection;
public function __construct(DBReadConnection $dbReadConnection, DBWriteConnection $dbWriteConnection)
{
$this->dbReadConnection = $dbReadConnection;
$this->dbWriteConnection = $dbWriteConnection;
}
}
// You can still use service location for example to grab instances
// but you will not pollute your classes itself by making use of it
// directly. Instead we'll grab instances from it and pass them into
// the consuming class
// [...]
$read = $registry->get('dbReadConnection');
$write = $registry->get('dbWriteConnection');
$dbConsumer = new DbConsumer($read, $write);
Should be a configuration class the solution? Or is there a smarter way to achieve a scalable registry pattern if it is possible?
That approach is encountered very often and you maybe have heard something about a DI-Container. Fabien Potencier writes the following:
A Dependency Injection Container is an object that knows how to instantiate and configure objects. And to be able to do its job, it needs to knows about the constructor arguments and the relationships between the objects.
The boundaries between a service locator and a DI-Container seem to be pretty blurry but I like the concept to think about it like that: A Service Locator hides the dependencies of a class while a DI-Container does not (which comes along with the benefit of easy unit testing).
So you see, there is no final answer and it depends on what you are building. I can suggest to dig more into the topic since how dependencies are managed is a core concern of every application.
Further Reading
Why Registry Pattern is antipattern. And what is alternative for it.
Service Locator is an Anti-Pattern
Do you need a Dependency Injection Container?

Inversion of Control with PHP

I just started using Dependency Injection for obvious reasons and without reading about Inversion of Control (IoC) quickly stumble with the issue of being verbose when instantiate some of my classes. So, reading about IoC I have a question that have not found an concrete answer. When should class registration happen? in a bootstrap? before execution? How can I enforce the type of the dependencies?
I am not using any frameworks. For the sake of learning I wrote my own container.
This is a very lowbrow example of my container and some sample classes.
class DepContainer
{
private static $registry = array();
public static function register($name, Closure $resolve)
{
self::$registry[$name] = $resolve;
}
public static function resolve($name)
{
if (self::registered($name)) {
$name = static::$registry[$name];
return $name();
}
throw new Exception('Nothing bro.');
}
public static function registered($name)
{
return array_key_exists($name, self::$registry);
}
}
class Bar
{
private $hello = 'hello world';
public function __construct()
{
# code...
}
public function out()
{
echo $this->hello . "\n";
}
}
class Foo
{
private $bar;
public function __construct()
{
$this->bar = DepContainer::resolve('Bar');
}
public function say()
{
$this->bar->out();
}
}
With these already in the app structure. The Dependecy Injection way I would do type hint the incoming parameters, but without it I can do:
DepContainer::register('Bar', function(){
return new Bar();
});
$f = new Foo();
$f->say();
To me, makes sense in a bootsrap register all dependencies it would be the more clean way IMO. At run time like a showed you I think is just as ugly as doing new Foo(new Bar(...)...).
I will try to summarize a few things that you should know and (hopefully) will clarify some of your dilemmas .
Let's start from a basic example:
class MySQLAdapter
{
public function __construct()
{
$this->pdo = new PDO();
}
}
class Logger
{
public function __construct()
{
$this->adapter = new MySqlAdapter();
}
}
$log = new Logger();
As you can see, we are instantiating Logger which has two dependencies: MySQLAdapter and PDO.
This process works like this:
We created Logger
Logger creates MySQLAdapter
MySQLAdapter creates PDO
The above code works, but if tomorrow we decided that we need to log our data in a file instead of a database, we will need
to change the Logger class and replace MySQLAdapter with a brand new FileAdapter.
// not good
class Logger
{
public function __construct()
{
$this->adapter = new FileAdapter();
}
}
This is the problem that Dependency Injection tries to solve: do not modify a class because a dependency has changed.
Dependency Injection
Di reefers to the process of instantiating a class by giving it's constructor all the dependencies it needs to function properly. If we apply Dependency
Injection to our previous example, it will look like this:
interface AdapterInterface
{
}
class FileAdapter implements AdapterInterface
{
public function __construct()
{
}
}
class MySQLAdapter implements AdapterInterface
{
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
}
class Logger
{
public function __construct(AdapterInterface $adapter)
{
$this->adapter = $adapter;
}
}
// log to mysql
$log = new Logger(
new MySQLAdapter(
new PDO()
)
);
As you can see, we don't instantiate anything in constructor, but we pass the instantiated class to constructor. This allows us to replace any dependency
without modifying the class:
// log to file
$log = new Logger(
new FileAdapter()
);
This helps us:
To easily maintain the code:
As you already saw, we don't need to modify the class if one of its dependencies changed.
Makes the code more testable:
When you run your test suite against MySQLAdapter you don't want to hit the database on each test, so the PDO object will be mocked in tests:
// test snippet
$log = new Logger(
new MySQLAdapter(
$this->getMockClass('PDO', [...])
)
);
Q: How does Logger knows that you give him a class that it needs and not some garbage ?
A: This is the interface (AdapterInterface) job, which is a contract between Logger and other classes. Logger "knows" that any class that implements
that particular interface will contain the methods it needs to do his job.
Dependency Injection Container:
You can look at this class (ie: container) as a central place where you store all your objects needed to run your application. When you need one of them,
you request the object from the container instead of instantiating yourself.
You can look at DiC as a dog who was trained to get out, get the newspaper and bring it back to you. The catch is that the dog was trained only with the front door opened.
Everything would be fine as long as the dog's dependencies will not change (ie door opened). If one day the front door will be closed, the dog will not know how to get the newspaper.
But if the dog would have an IoC container, he could find a way ...
Inversion of Control
As you saw until now, the initialization process of the "classic" code was:
We created Logger
Logger creates MySQLAdapter
MySQLAdapter creates PDO
IoC simply replicates the above process, but in reverse order:
Create PDO
Create MySQLAdapter and give him PDO
Create Logger and give him MySQLAdapter
If you though that Dependency Injection is some kind of IoC, you are right. When we talked about Dependency Injection, we had this example:
// log to mysql
$log = new Logger(
new MySQLAdapter(
new PDO()
)
);
At a first look someone could say that the instantiation process is:
Create Logger
Create MySQLAdapter
Create PDO`
The thing is that the code will be interpreted from the middle to the left. So the order will be:
Create PDO
Create MySQLAdapted and give him PDO
Create Logger and give him MySQLAdapter
The IoC container simply automates this process. When you request Logger from the container, it uses PHP Reflection and type hinting to analyze its dependencies (from constructor), instantiate all of them, sends them to the requested class and gives you back a Logger instance.
NOTE: To find out what dependencies a class has, some IoC containers are using annotations instead of type hinting or a combination of both.
So to answer your question:
If the container can resolve the dependencies by itself, you would only need to instantiate the container during the boot
process of your application. (see Inversion of Control container)
If the container can't resolve the dependencies by itself, you would need to manually provision the container with the objects needed to run your application. This provisioning usually happens during the boot process. (see Dependency Injection Container)
If your container can resolve the dependencies by itself, but for various reasons you also need to manually add more dependencies, you would do that in
the boot process, after you initialize the container.
NOTE: In the wild there are all kind of mixes between these two principles, but I tried to explain you what is the main idea behind each of them.
How your container will look depends only by you and don't be afraid to reinvent the wheel as long as you do it for educational purposes.

How to test a Factory / Strategy implementation with PHPUnit

I have a Factory class that returns a writer strategy based on the extension of a given file:
public static function getWriterForFile($file)
{
// create file info object
$fileInfo = new \SplFileInfo($file);
// check that an extension is present
if ('' === $extension = $fileInfo->getExtension()) {
throw new \RuntimeException(
'No extension found in target file: ' . $file
);
}
// build a class name using the file extension
$className = 'MyNamespace\Writer\Strategy\\'
. ucfirst(strtolower($extension))
. 'Writer';
// attempt to get an instance of the class
if (!in_array($className, get_declared_classes())) {
throw new \RuntimeException(
'No writer could be found for the extension: ' . $extension
);
}
$instance = new $className();
$instance->setTargetFile($file);
return $instance;
}
All of my strategies implement the same interface, for example:
class CsvWriter implements WriterStrategyInterface
{
public function setTargetFile($file)
{
...
}
public function writeLine(array $data)
{
...
}
public function flush()
{
...
}
}
I want to be able to test this method using a dummy extension so that my tests are not dependant on any particular strategy existing. I tried creating a mock for the interface with a set classname, but this does not seem to have declared the mock class name:
public function testExpectedWriterStrategyReturned()
{
$mockWriter = $this->getMock(
'MyNamespace\Writer\Strategy\WriterStrategyInterface',
array(),
array(),
'SssWriter'
);
$file = 'extension.sss';
$writer = MyNamespace\Writer\WriterFactory::getWriterForFile($file);
$this->assertInstanceOf('MyNamespace\Writer\Strategy\WriterStrategyInterface', $writer);;
}
Is there any way for me to stage a mock writer strategy for the factory to load, or should I refactor the factory method to make it more testable?
The main purpose and responsibility for that factory is the creation of objects.
Imho you should test that using
$this->assertInstanceOf('class', $factory->getWriterForFile($file));
Why not abstract further?
You could beimplementation in a way so that the factory dispatches the object creation to another class.
Having a "object creator" that does:
$class = new ReflectionClass($class);
$instance = $class->newInstanceArgs($args);
or something along those lines but what is your gain apart from "well the test looks more like a unit test"? You're not improving really improving your code base and changes just for test-abilities sake always smell a little funny to me.
I'd treat factory tests as integration/wiring tests that make sure all your factory actually work and produce the desired objects.
The only change I'd suggest for your current code sample would be to change two things:
a) make the factory method non static
If you don't have a very good reason you don't gain anything from a static factory except that you can't inject it and making it static makes it accessible from global scope so getting dependencies into the factory will require even more globals and so on. If you do DI with factories usually making them proper objects too helps avoiding issues down the road
b) Don't do diskIo in the factory. Use: getWriterForFile(\SplFileInfo $file)
The factory should not care about the file system. If it needs a existing file it should require one and leave the details of how to handle the error to the consumers.
That gives you the benefit that you can also pass a SplTempFileObject which will make testing easier and allow your factories to be independent of the file system even for production purposes.

Micro-Dependencies, Avoiding Coupling, and Objects Creating Objects [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Dependency Hell — how does one pass dependencies to deeply nested objects?
In a system built around strong dependency injection, I'm wondering how to deal with a contrived situation like this:
<?php
class LogWriter
{
public function write(Log $log)
{
echo $log->getMessage();
}
}
class Log
{
private $message;
public function setMessage($message)
{
$this->message = $message;
}
public function getMessage()
{
return $this->message;
}
}
class Logger
{
private $writer;
public function __construct(LogWriter $writer)
{
$this->writer = $writer;
}
public function write($message)
{
// Here is the dependency
$log = new Log();
$log->setMessage($message);
$this->writer->write($log);
}
}
The Logger::write() method creates an instance of Log, and passes it to the log writer. My gut tells me that's a bad approach, and a month from now I'm going to be tracking down a bug related to it, and I might want to switch the Log class for something else during testing.
But how to avoid it? The only thing that comes to mind is passing a Log type to the Logger constructor, and changing my Logger class to this:
class Logger
{
private $writer;
private $log_type;
public function __construct(LogWriter $writer, $log_type)
{
$this->writer = $writer;
$this->log_type = $log_type;
}
public function write($message)
{
$log = new $this->log_type();
$log->setMessage($message);
$this->writer->write($log);
}
}
And then creating a new Logger instance like this:
$log_writer = new LogWriter();
$logger = new Logger($log_writer, "Log");
But that feels a bit hackish. So how do you deal with micro-dependencies like this?
Note: I'm using the logging classes as an example, and I'm not looking for a solution to this exact problem. I would probably just use an array instead of the Log class.
Edit: In a more complex situation, I might pass a dependency injection container to the Logger class, and use that to create an instance of Log, but that seems overly complicated for a simple logger class.
Since your Log object is really just a Data Transfer Object or Value Object, you can create it inside the Logger class. It's okay to do so in this case. You dont need to pass anything to the Logger. But you are right in that you wont be able to mock/stub this easily then.
As an alternative, you could also inject a Factory if you want to decouple the Log class from the Logger:
$logger = new Logger($logWriter, new LogFactory);
and then create the Log Type from there:
public function write($message)
{
$log = $this->logFactory->createNew();
…
This capsules the creation logic inside the Factory class. The Factory will still have the Log type hardcoded inside, but it's okay for Factories to have that. You then just test that it returns the right type when you call createNew. And in your consumers, you can stub that call.
If you dont feel like creating a full-blown Factory class for this, you can also use a Lambda instead of a Factory. Since it captures the essential creation logic, it's effectively the same as a Factory, just without a class:
$logger = new Logger($logWriter, function() { return new Log; });
And then
public function write($message)
{
$log = call_user_func($this->createLogCallback);
…
Both, the Factoy and the Lambda approach allow for substituting the Log type in your Unit-Test. Then again, substituting the Log type doesn't seem that necessary in your scenario. The Log type doesn't have any dependencies of it's own, so you can pretty much use the real deal here. You can easily verify your write method by simply looking at what gets written by the LogWriter. You won't have an explicit assertion on a Log Mock, but if the writer produces the expected output for the given input to write, you can safely assume that the Log type collaborates as expected.
Also see http://misko.hevery.com/2008/09/30/to-new-or-not-to-new for more details.

Dependency Injection: pulling required components when they are actually needed

The gist behind DI is to relieve a class from creating and preparing objects it depends on and pushing them in. This sounds very reasonable, but sometimes a class does not need all the objects, that are being pushed into it to carry out its function. The reason behind this is an "early return" that happens upon invalid user input or an exception thrown by one of the required objects earlier or the unavailability of a certain value necessary to instantiate an object until a block of code runs.
More practical examples:
injecting a database connection object that will never be used, because the user data does not pass validation (provided that no triggers are used to validate this data)
injecting excel-like objects (PHPExcel e.g.) that collect input (heavy to load and instantiate because a whole library is pulled in and never used, because validation throws an exception earlier than a write occurs)
a variable value that is determined within a class, but not the injector at runtime; for instance, a routing component that determines the controller (or command) class and method that should be called based on user input
although this might be a design problem, but a substantial service-class, that depends on a lot of components, but uses only like 1/3 of them per request (the reason, why i tend to use command classes instead of controllers)
So, in a way pushing in all necessary components contradicts "lazy-loading" in the way that some components are created and never used, that being a bit unpractical and impacting performance. As far as PHP is concerned - more files are loaded, parsed and compiled. This is especially painful, if the objects being pushed in have their own dependencies.
i see 3 ways around it, 2 of which don't sound very well:
injecting a factory
injecting the injector (an anti-pattern)
injecting some external function, that gets called from within the
class once a relevant point is reached (smtg like "retrieve a
PHPExcel instance once data validation finished"); this is what i
tend to use due to its flexibility
The question is what's the best way of dealing with such situations / what do you guys use?
UPDATE:
#GordonM here are the examples of 3 approaches:
//inject factory example
interface IFactory{
function factory();
}
class Bartender{
protected $_factory;
public function __construct(IFactory $f){
$this->_factory = $f;
}
public function order($data){
//validating $data
//... return or throw exception
//validation passed, order must be saved
$db = $this->_factory->factory(); //! factory instance * num necessary components
$db->insert('orders', $data);
//...
}
}
/*
inject provider example
assuming that the provider prepares necessary objects
(i.e. injects their dependencies as well)
*/
interface IProvider{
function get($uid);
}
class Router{
protected $_provider;
public function __construct(IProvider $p){
$this->_provider = $p;
}
public function route($str){
//... match $str against routes to resolve class and method
$inst = $this->_provider->get($class);
//...
}
}
//inject callback (old fashion way)
class MyProvider{
protected $_db;
public function getDb(){
$this->_db = $this->_db ? $this->_db : new mysqli();
return $this->_db;
}
}
class Bartender{
protected $_db;
public function __construct(array $callback){
$this->_db = $callback;
}
public function order($data){
//validating $data
//... return or throw exception
//validation passed, order must be saved
$db = call_user_func_array($this->_db, array());
$db->insert('orders', $data);
//...
}
}
//the way it works under the hood:
$provider = new MyProvider();
$db = array($provider, 'getDb');
new Bartender($db);
//inject callback (the PHP 5.3 way)
class Bartender{
protected $_db;
public function __construct(Closure $callback){
$this->_db = $callback;
}
public function order($data){
//validating $data
//... return or throw exception
//validation passed, order must be saved
$db = call_user_func_array($this->_db, array());
$db->insert('orders', $data);
//...
}
}
//the way it works under the hood:
static $conn = null;
$db = function() use ($conn){
$conn = $conn ? $conn : new mysqli();
return $conn;
};
new Bartender($db);
I've been thinking about this problem a lot lately in planning of a major project that I want to do as right as humanly possible (stick to LoD, no hard coded dependencies, etc). My first thought was the "Inject a factory" approach as well, but I'm not sure that's the way to go. The Clean Code talks from Google made the claim that if you reach through an object to get the object you really want then you're violating the LoD. That would seem to rule out the idea of injecting a factory, because you have to reach through the factory to get what you really want. Maybe I've missed some point there that makes it okay, but until I know for sure I'm pondering other approaches.
How do you do the function injection? I'd imagine you're passing in a callback that does the instantiation of the object you want, but a code example would be nice.
If you could update your question with code examples of how you do the three styles you mentioned it might be useful. I'm especially keen to see "injecting the injector" even if it is an antipattern.
One idea that did occur was that of a proxy object. It implements the same interface(s) as the actual object you want to pass in, but instead of implementing anything it just holds an instance of the real class and forwards method calls on to it.
interface MyInterface
{
public function doFoo ();
public function isFoo ();
// etc
}
class RealClass implements MyInterface
{
public function doFoo ()
{
return ('Foo!');
}
public function isFoo ()
{
return ($this -> doFoo () == 'Foo!'? true: false);
}
// etc
}
class RealClassProxy implements MyInterface
{
private $instance = NULL;
/**
* Do lazy instantiation of the real class
*
* #return RealClass
*/
private function getRealClass ()
{
if ($this -> instance === NULL)
{
$this -> instance = new RealClass ();
}
return $this -> instance;
}
public function doFoo ()
{
return $this -> getRealClass () -> doFoo ();
}
public function isFoo ()
{
return $this -> getRealClass () -> isFoo ();
}
// etc
}
Because the proxy has the same interface as the real class, you can pass it as an argument to any function/method that type hints for the interface. The Liskov Substitution Principle holds for the proxy because it responds to all the same messages as the real class and returns the same results (the interface enforces this, at least for method signitures). However, the real class doesn't get instantiated unless a message actually gets sent to the proxy, which does lazy instantiation of the real class behind the scenes.
function sendMessageToRealClass (MyInterface $instance)
{
$instance -> doFoo ();
}
sendMessageToRealClass (new RealClass ());
sendMessageToRealClass (new RealClassProxy ());
There is an extra layer of indirection involved with the proxy object, which obviously means that there is a small performance hit for every method call you make. However, it does allow you to do lazy instantiation, so you can avoid instantiating classes you don't need. Whether this is worth it depends on the cost of instantiating the real object versus the cost of the extra layer of indirection.
EDIT: I had originally written this answer with the idea of subclassing the real object so you could use the technique with objects that don't implement any interfaces such as PDO. I had originally thought that interfaces were the correct way to do this but I wanted an approach that didn't rely on the class being tied to an interface. On reflection that was a big mistake so I've updated the answer to reflect what I should have done in the first place. This version does mean, however, that you can't directly apply this technique to classes with no associated interface. You'll have to wrap such classes in another class that does provide an interface for the proxy approach to be viable, meaning yet another layer of indirection.
If you want to implement lazy loading you basically have two way to do it (as you have already written in the topic):
instead of injecting an instance of object you might need, you inject a Factory or a Builder. The difference between them is that instance of Builder is made for returning one type of object (maybe with different setups), while Factory makes different types of instances ( with same lifetime and/or implementing same interface ).
utilize anonymous function which will return you an instance. That would look something like this:
$provider = function() {
return new \PDO('sqlite::memory:');
};
Only when you call this anonymous function, the instance of PDO is created and connection to database established.
What I usually do in my code is combine both. You can equip the Factory with such provider. This, for example, lets you have a single connection for all the objects which where created by said factory, and the connection is create only, when you first time ask an instance from Factory.
The other way to combine both methods (which i have not used, though) would be to create full blow Provider class, which in constructor accepts an anonymous function. Then the factory could pass around this same instance of Provider and the expensive object (PHPExcel, Doctrine, SwiftMailer or some other instance) is only created once a Product from that Factory first time turns to the Provider (couldn't come up with better name to describe all objects created by same factory) and requests it. After that, this expensive object is shared between all Products of Factory.
... my 2 cents
I chose lazy-injection (i.e. injecting a Proxy class):
class Class1 {
/**
* #Inject(lazy=true)
* #var Class2
*/
private $class2;
public function doSomething() {
// The dependency is loaded NOW
return $this->class2->getSomethingElse();
}
Here, the dependency (class2) is not injected directly: a proxy class is injected. Only when the proxy class is used that the dependency is loaded.
This is possible in PHP-DI (dependency injection framework).
Disclaimer: I work in this project

Categories