Skip to content
This repository has been archived by the owner on Feb 6, 2020. It is now read-only.

Commit

Permalink
Merge branch 'hotfix/148' into develop
Browse files Browse the repository at this point in the history
Close #150
Fixes #148
  • Loading branch information
weierophinney committed Sep 15, 2016
2 parents 972b03b + e6d0c3e commit cd97cd1
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ All notable changes to this project will be documented in this file, in reverse
`config` service, if present.
- All other array values will be provided an empty array.
- Class/interface typehints will be pulled from the container.
- [#150](https://github.com/zendframework/zend-servicemanager/pull/150) adds
a "cookbook" section to the documentation, with an initial document detailing
the pros and cons of abstract factory usage.

### Deprecated

Expand Down
98 changes: 98 additions & 0 deletions doc/book/cookbook/factories-vs-abstract-factories.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# When To Use Factories vs Abstract Factories

Starting with version 3, `Zend\ServiceManager\Factory\AbstractFactoryInterface`
extends `Zend\ServiceManager\Factory\FactoryInterface`, meaning they may be used
as either an abstract factory, or mapped to a specific service name as its
factory.

As an example:

```php
return [
'factories' => [
SomeService::class => AnAbstractFactory::class,
],
];
```

Why would you choose one approach over the other?

## Comparisons

Approach | Pros | Cons
---------------- | -------------- | ----
Abstract factory | One-time setup | Performance; discovery of code responsible for creating instance
Factory | Performance; explicit mapping to factory responsible | Additional (duplicate) setup

Essentially, it comes down to *convenience* versus *explicitness* and/or
*performance*.

## Convenience

Writing a factory per service is time consuming, and, particularly in early
stages of an application, can distract from the actual business of writing the
classes and implementations; in addition, since requirements are often changing
regularly, this boiler-plate code can be a nuisance.

In such situations, one or more abstract factories — such as the
[ConfigAbstractFactory](../config-abstract-factory.md), the
[ReflectionBasedAbstractFactory](../reflection-abstract-factory.md), or the
[zend-mvc LazyControllerAbstractFactory](https://docs.zendframework.com/zend-mvc/cookbook/automating-controller-factories/)
— that can handle the bulk of your needs are often worthwhile, saving you
time and effort as you code.

## Explicitness

The drawback of abstract factories is that lookups by the service manager take
longer, and increase based on the number of abstract factories in the system.
The service manager is optimized to locate *factories*, as it can do an
immediate hash table lookup; abstract factories involve:

- Looping through each abstract factory
- invoking its method for service location
- if the service is located, using the factory

This means, internally:

- a hash table lookup (for the abstract factory)
- invocation of 1:N methods for discovery
- which may contain additional lookups and/or retrievals in the container
- invocation of a factory method (assuming succesful lookup)

As such, having an explicit map can aid performance dramatically.

Additionally, having an explicit map can aid in understanding what class is
responsible for initializing a given service. Without an explicit map, you need
to identify all possible abstract factories, and determine which one is capable
of handling the specific service; in some cases, multiple factories might be
able to, which means you additionally need to know the *order* in which they
will be queried.

The primary drawback is that you also end up with potentially duplicate
information in your configuration:

- Multiple services mapped to the same factory.
- In cases such as the `ConfigAbstractFactory`, additional configuration
detailing how to create the service.

## Tradeoffs

What it comes down to is which development aspects your organization or project
favor. Hopefully the above arguments detail what tradeoffs occur, so you may
make an appropriate choice.

## Tooling

Starting with 3.2.0, we began offering a variety of [console tools](../console-tools.md)
to assist you in generating both dependency configuration and factories. Use
these to help your code evolve. An expected workflow in your application
development evolution is:

- Usage of the `ReflectionBasedAbstractFactory` as a "catch-all", so that you
do not need to do any factory/dependency configuration immediately.
- Usage of the `ConfigAbstractFactory`, mapped to services, once dependencies
have settled, to disambiguate dependencies, or to list custom services
returning scalar or array values.
- Finally, usage of the `generate-factory-for-class` vendor binary to generate
actual factory classes for your production-ready code, providing the best
performance.
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ pages:
- 'Configuration-based Abstract Factory': config-abstract-factory.md
- 'Reflection-based Abstract Factory': reflection-abstract-factory.md
- 'Console Tools': console-tools.md
- Cookbook:
- 'Factories vs Abstract Factories': cookbook/factories-vs-abstract-factories.md
- 'Migration Guide': migration.md
site_name: zend-servicemanager
site_description: 'zend-servicemanager: factory-driven dependency injection container'
Expand Down

0 comments on commit cd97cd1

Please sign in to comment.