The common patterns dealing with object creation are the Gang of Four Creational Patterns.
Quoting Wikipedia:
Creational patterns are ones that create objects for you, rather than having you instantiate objects directly. This gives your program more flexibility in deciding which objects need to be created for a given case.
- Abstract Factory groups object factories that have a common theme.
- Builder constructs complex objects by separating construction and representation.
- Factory Method creates objects without specifying the exact class to create.
- Prototype creates objects by cloning an existing object.
- Singleton restricts object creation for a class to only one instance.
For a general rule of thumb where to put the responsibility to create an instance, have a look at the Creator pattern in Wikipedia's article about GRASP:
In general, a class B should be responsible for creating instances of class A if one, or preferably more, of the following apply:
- Instances of B contain or compositely aggregate 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.
The GoF Creational Patterns complement this. For instance, if you use a Factory pattern, the Factory is likely to hold the initializing information for instances of A and will pass it on creation:
class BMWFactory implements CarFactory
{
// properties, ctors and stuff …
public function createCar($color)
{
return new Bmw(
$color,
// … more arguments
);
}
}
On the other hand, it also means that a Collection may be allowed to create new instances because B then "contains or compositely aggregate instances of A.", which would lead to something like
class Cars
{
// properties, ctors and stuff …
public function createCar($color)
{
return new Car(/* … */);
}
}
$bmws = new Cars($config['bmw']);
$bmws[] = $bmws->createCar('alpine white');
We could argue whether it's a good idea to have your collections create objects over just storing them when the created objects have an independent lifecycle. If the As created by B have the same lifetime, it's a different thing.
Instead of having B create As, you could also delegate the creation to a Factory:
class Cars
{
// properties, ctors and stuff …
public function createCar($color)
{
return $this->carFactory->createNewCar(/* … */);
}
}
$bmws = new Cars(new BmwFactory);
$bmws[] = $bmws->createCar('alpine white');
The reason why you should always carefully consider where to to use new
in your code is because it introduces strong coupling from B to A. Injecting the Factory loosens that coupling, especially since we programmed to an interface instead of the concrete Class.
Strong coupling makes it difficult to mock collaborators in your unit-tests. Quoting Miško Hevery's How to Think About the “new” Operator with Respect to Unit Testing
But the reason why Dependency Injection is so important is that within unit-tests you want to test a small subset of your application. The requirement is that you can construct that small subset of the application independently of the whole system. If you mix application logic with graph construction (the new operator) unit-testing becomes impossible for anything but the leaf nodes in your application.
The idea of separating creation from application logic is further explained in his Google Talk, which is linked in my related answer Dependency Hell — how does one pass dependencies to deeply nested objects?. The basic idea is to assemble everything you can reasonably assemble up-front in Factories or Builders or via a Dependency Injection Container.
TL;DR
if you want to create objects in a local scope (because it depends on runtime information), encapsulate the Creation logic into Factories or Builders and inject these into the objects that hold the runtime information and delegate the information to the Factories and Builders from there when needed.