I just learned about dependency injection. But I come across this problem: because some of my class's dependent objects can be very large number, passing all of them to the class constructor can be very long and not clear, example,
interface FooInterface {
function fooMethod();
}
class Foo implements FooInterface {
function fooMethod(){
return 'Foo';
}
}
class Boo
{
public $foo;
public function __construct(FooInterface $foo) // This one is ok because it depends on one object only,
{
$this->foo = $foo;
}
}
class BooFactory
{
public static function create()
{
return new Boo(new Foo);
}
}
$a = new BooFactory;
$b = $a->create();
var_dump($b->foo->fooMethod());
What if it depends on lots of objects,
class Boo
{
public function __construct(FooInterface $foo, TooInterface $boo, PooInterface $poo, etc, etc ,etc, etc, etc)
{
//
}
}
It looks too much don't you think? Or is it normal? Or what else should I do instead?
If your class is actually has a hard dependency (i.e. not an optional dependency) on all those objects, then it's valid to do this. If some of the dependencies are optional (e.g. Maybe you can inject a logger, but if it's not present you just don't perform any logging), then consider removing them from the constructor and using setter injection instead.
Setter injection is where you'd add the $foo property to your class as normal, but omit it from the constructor's parameters. Then you'd provide a setFoo(Foo $foo) method to your class so that you can inject a Foo instance if required.
When a class has a very long list of arguments, it can be a "code smell" that your class is trying to do too much and possibly not following the single responsibility principle. If your class is trying to do too much, consider refactoring your code into a number of smaller classes that consume each other.
Related
I'm trying to write an abstract class (or interface) which forces the extending class to implement a protected static function.
But this is neither possible with an abstract class nor an interface.
Errors:
static functions should not be abstract
access type for interface members must be omitted
Any ideas how to accomplish that?
UPDATE
The purpose is basically to call the public function statically. This way the class does not need to be instanciated.
It is also not necessary to make _doSpecificStuff() callable from class-external code.
abstract class Foo
{
public static function doStuff()
{
[generic code]
static::_doSpecificStuff();
}
// sth like that would be nice to have:
abstract static protected function _doSpecificStuff();
}
From a theoretical as well as a practical standpoint, there's no real need to declare a static method abstract.
Abstract methods are there to have a child class fill in a blank. That's typically because the parent class (the original abstract class) does some generic operation, but can/must be adapted to certain specific situations and can thus force child classes to implement only this particular variable part in the otherwise generic algorithm. Abstract methods are supposed to be a blank spot within a larger algorithm.
A parent method would call implementations of its abstract methods without knowing or caring who implements them or how they're implemented:
abstract class Foo {
public function someAlgo() {
$foo = $this->doSomethingSpecific();
...
}
abstract protected function doSomethingSpecific();
}
Foo doesn't care who or what fills in the blank doSomethingSpecific, it just relies on it being there and its signature, which abstract enforces. The specific object which implements this method or how it implements it is variable. This is important and is at the core of the issue.
Declaring a static method abstract is pretty useless in this scenario. Any static method can just as well be implemented as a non-static method, so there's no use for it here. If the class itself is supposed to call the abstract method as part of a larger generic algorithm as described above, there's no need for a static method.
So the only scenario left for a static method is for a public static method which is callable from anywhere:
abstract class Foo {
abstract public static function bar();
}
class Baz extends Foo {
public static function bar() { ... }
}
Baz::bar();
The thing is, since the abstract class Foo is not itself calling this function but this function is only called from external code, you're not really talking about a fill-in-the-blank method, you're talking about an interface. So, you should be using an interface instead.
But even there, since you have to type the specific class name in your source code, hardcoded, there's little point for an interface as well.
The point of declaring an interface or abstract method signature is that you want to fix the method signature so any code can call that particular method without caring what object it's calling it on in particular. But since you have to hardcode the class name, there's no variability in the object you're calling it on. If you type Baz::bar(), you know exactly what class you're calling what method on. Therefore there's little point in abstracting the interface/signature.
Compare:
interface FooInterface {
public function bar();
}
function baz(FooInterface $foo) {
$foo->bar();
}
The function baz can rely on its argument having a bar() method due to the interface declaration. The specific object that's implementing the method is irrelevant and will vary.
abstract class Foo {
public function someAlgo() {
$foo = $this->doSomethingSpecific();
...
}
abstract protected function doSomethingSpecific();
}
The class Foo can rely on it having the doSomethingSpecific method. The specific object that's implementing the method is irrelevant and will vary.
abstract class Foo {
abstract public static function bar();
}
class Baz extends Foo {
public static function bar() { ... }
}
Baz::bar();
What exactly are you relying on or abstracting here? You can be pretty darn sure Baz will have the method bar() every time, because you're only ever calling it on the same hardcoded class. Nothing is variable here.
Assuming that I have to create a class that takes some text do some processing and return it ... with no dependency and it's a stateless class..
I'd like to know would be better to create a stateless class without constructor or just create a static class (in php it's just Static methods)
class like this:
class ClassName
{
public function processText($text)
{
// Some code
$text = $this->moreProcessing($text);
return $text;
}
protected function moreProcessing($text)
{
return $text;
}
}
and this:
class ClassName
{
public static function processText($text)
{
// Some code
$text = static::moreProcessing($text);
return $text;
}
protected static function moreProcessing($text)
{
return $text;
}
}
I Know that dependency injection into the class where these classes are used would be better but assume that I just won't have dependency injection..
My question is mainly would it be better to create static class for the simple example above?
Practically you will see no difference whatsoever.
It's only in the syntax, and the ability of a constructor to perform stuff automatically, though you still have to create instances to invoke the constructor, which in this case is not far off calling some equivalent static member function.
However, non-static member functions are supposed to affect internal state so, if you have no state, static member functions seem more conventional, and will be slightly less surprising to users of the class.
The best approach, though, is to stick your functions in a namespace. Classes are for data and functions operating on that data... even static ones.
I have a set of independent functions which I want to put in a class.
They do not depend on any objects of the class, so while calling them, all the values required would be passed as arguments.
Is it fine if I declare all of them as static so that i can call them with just one command like className::functionName(argument1,argument2,...)
or do i keep them as normal public function and call them through a class object?
You can (but you shouldn't do it):
class YourClass {
public static function yourMethod( ) {
echo "method called";
}
}
YourClass::yourMethod();
The reason why you shouldn't do it is because when you use the static call in some other class / function / whatever you have tightly coupled the YourClass to the other class. hence you are making it pretty hard to do unit tests or simply switch to another moethod without going trhough all the code where it is used. And also don't forget you just added something globally.
You also say:
I have a set of independent functions which I want to put in a class.
This is a big code smell in my book. This makes it sound like your class violates the SRP principle in SOLID programming.
Hence I would just instantiate the class.
Let's see why it makes your code hard to test:
class SomeClassWithMethods
{
public static function doSomething()
{
}
}
class SomeClassYouWantToTest
{
public function doSomething()
{
return SomeClassWithMethods::doSomething(); // this is now tightly coupled and would be impossible to mock when unit testing it
}
}
Also that that SomeClassWithMethods::doSomething is now globally defined.
We like to call this the silver bullet :) :
Yes this is not bad.
You can define them as static functions and like you said - you can call them with just one statement.
class Foo {
public static function bar( ) {
echo "bar called";
}
}
Can we create an object of a class inside another class in php?I hav made a small application in php,now I am trying to convert the entire code in a class-methods-object fashion.I m now Confused.
You you can do that, but whether you should depends on the lifetime of the two classes and their relation to each other. Basically, you have the choice between Composition and Aggregation.
Composition
You use Composition when the created object has a lifetime equal or less than the object that will use it, e.g.
class A
{
private $belongsToAOnly;
public function __construct()
{
$this->belongsToAOnly = new IBelongToA;
}
}
In this case A "owns" IBelongToA. When A is destroyed, IBelongToA is destroyed too. It cannot live on it's own and is likely just an implementation detail of A. It could be a ValueObject like Money or some other Data Type.
From Craig Larman's "Applying UML and Patterns":
the composite is responsible for creation and deletion of it's parts - either by itself creating/deleting the parts, or by collaborating with other objects. Related to this constraint is that if the composite is destroyed, its parts must be destroyed, or attached to another composite"
Aggregation
You use Aggregation when the lifetime of the created object is longer:
class A
{
private $dbAdapter;
public function __construct(DbAdapter $dbAdapter)
{
$this->dbAdapter = $dbAdapter;
}
}
Unlike with Composition, there is no implication of ownership here. A uses DbAdapter but when A is destroyed DBAdapter lives on. It's a "uses" relationship instead of an "owns" relationship.
Creator Pattern (GRASP)
A good heuristic to decide when an object may create another object at runtime can be found in the Creator Pattern in GRASP which states that objects may create other objects when
Instances of B contains or compositely aggregates instances of A
Instances of B record instances of A
Instances of B closely use instances of A
Instances of B have the initializing information for instances of A and pass it on creation.
Alternatively, you can create Factories whenever you need to create instances of something and aggregate the factory instances, which will give you a cleaner separation of collaborators and creators.
Testability
An issue stemming from creating objects within objects is that they are difficult to test. When you do unit-testing, you usually do not want to recreate and bootstrap the entire system environment but concentrate on testing just that particular class in isolation. To do that, you swap out dependencies of that class with Mock Objects. You cannot do that when you use Composition.
So depending on what the collaborators of a class do, you might want to decide to always use Aggregation, because then you are effectively doing Dependency Injection all the way, which will allow you to swap out collaborators of a class easily, for instance to replace them with Mocks.
Yes you can, but that increases code coupling and makes testing harder.
I'd suggest creating it outside the class and pass it as an argument (it is called Dependency Injection).
class Foo
{
}
class Bar
{
public function __construct(Foo $foo)
{
$this->foo = $foo;
}
}
$foo = new Foo();
$bar = new Bar($foo);
yes you can do it ..
here is one example..
a.php
<?php
class a{
public function function_1(){
echo "b";
}
}
?>
b.php
<?php
include_once ("a.php");
class b{
public function function_b(){
$a = new a;
$a->function_1();
}
}
$b= new b;
$b->function_b();
?>
Yes, you can create an object from a specific class from inside another class.
class SomeClass{
}
class SomeOtherClass {
function hello(){
$o = new SomeClass;
}
}
Yes, you can also define a function in a class. You can do everything in a class in php, please post your code where you confused.
Examples:
Object in a class.
class Foo
{
public $bar; // another object!
public __construct()
{
$this->bar = new Bar();
}
}
(global)Function in a class
<?php
class Foo
{
public function __construct()
{
function __construct()
{
echo "Yes, I'm a global function!";
}
}
}
new Foo();
__construct();
?>
I'm trying to figure out the best practices for dependency injection in PHP.
Question: Do I have to inject all dependencies of a subclass into the parent class? I use the terms 'parent' and 'child' in terms of a composition relationship.
My hesitation is because I find myself giving the parent class all kinds of dependencies so that it can just pass them down to dependent child classes.
Edit:
Below is a more concrete example of what I'm talking about. MyClassA does not need the database connection object or the logger. DoSomething does need these objects, however. What is the best way to get the database connection and logger to the DoSomething instance? I don't want to use singleton objects or global objects for the sake of unit testing. Also, this example only uses to classes. What if there are 3 or 4 and the 3rd or 4th needs some object instance but the first 2 or 3 don't? Does MyClassA just pass the object to the next, and so on?
class MyClassA {
protected $_doSomethingObject;
public function doSomething()
{
return $this->_doSomethingObject()->doSomethingElse();
}
public function setDoSomethingObject($doSomethingObject)
{
$this->_doSomethingObject = $doSomethingObject;
}
}
class DoSomething {
protected $_logger;
protected $_db;
public function doSomethingElse()
{
$this->_logger->info('Doing Something');
$result = $this->_db->getSomeDataById();
return $results;
}
public function setLogger($logger)
{
$this->_logger = $logger;
}
public function setDBConection($db)
{
$this->_db = $db;
}
}
Is the best way the example I show below? If so, then the best way is to work backwards so to speak...?
$logger = new Logger();
$db = new DBConnection();
$doSomething = new DoSomething();
$doSomething->setLogger($logger);
$doSomething->setDBConnection($db);
$a = new MyClassA();
$a->setDoSomething($doSomething);
If so, then the best way is to work backwards so to speak...?
Yes. As I mentioned in the comment, you set up the inner most objects first.
If an object create another object internally that isn't exposed, then it could pass along its injected objects if appropriate. For example:
class DoSomething {
// ...
public function foo() {
$foo = new Foo();
$foo->setLogger($this->_logger);
return $foo->bar();
}
}
However, if that secret Foo object needed references to other things that DoSomething didn't have, then you've got design issues. If that happens you need to do whatever is appropriate:
Inject a foo object into the parent object prior to calling foo().
Inject that dependency into the parent object prior to calling foo().
Add the dependency as a function argument.
Refactor code into a better design that doesn't create that problem.
You need only include the dependancies in the classes that are going to directly need them. Since the required/included files will be loaded whenever the base class loads, they will automatically be available to any child classes.