Skip to content

Commit

Permalink
Merge pull request #27 from mindplay-dk/3.0.0
Browse files Browse the repository at this point in the history
3.0.0
  • Loading branch information
mindplay-dk authored Nov 28, 2022
2 parents 70ced92 + e3d0ca3 commit 5a54bb1
Show file tree
Hide file tree
Showing 19 changed files with 941 additions and 373 deletions.
21 changes: 9 additions & 12 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,17 @@ dist: xenial

jobs:
include:
- php: 5.5
dist: trusty
- php: 5.6
- php: 7.0
- php: 7.1
- php: 7.2
- php: 7.3
- php: 7.4
env:
- XDEBUG_MODE=coverage
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover test/build/clover.xml
- php: 8.0

before_script:
- 'composer install --dev --prefer-source'
- composer install --dev --prefer-source

script: php test/test.php

after_script:
- if [ $(phpenv version-name) = "5.6" ]; then wget https://scrutinizer-ci.com/ocular.phar; fi
- if [ $(phpenv version-name) = "5.6" ]; then php ocular.phar code-coverage:upload --format=php-clover test/build/clover.xml; fi
script:
- php test/test.php
122 changes: 98 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
![Unbox](unbox-logo.png)

[![PHP Version](https://img.shields.io/badge/php-5.5%2B-blue.svg)](https://packagist.org/packages/mindplay/unbox)
[![Build Status](https://travis-ci.org/mindplay-dk/unbox.svg?branch=master)](https://travis-ci.org/mindplay-dk/unbox)
[![PHP Version](https://img.shields.io/badge/php-7.3%2B%20%7C%208.0%2B-blue.svg)](https://packagist.org/packages/mindplay/unbox)
[![Build Status](https://travis-ci.com/mindplay-dk/unbox.svg?branch=master)](https://travis-ci.org/mindplay-dk/unbox)
[![Code Coverage](https://scrutinizer-ci.com/g/mindplay-dk/unbox/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/mindplay-dk/unbox/?branch=master)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/mindplay-dk/unbox/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/mindplay-dk/unbox/?branch=master)

Expand Down Expand Up @@ -166,6 +166,8 @@ configure(string $name, callable $func, array $map) # ... with custom argumen

ref(string $name) : BoxedValueInterface # create a boxed reference to a component

registerFallback(ContainerInterface $container) # register a fallack container

createContainer() : Container # create a bootstrapped Container instance
```

Expand Down Expand Up @@ -523,9 +525,83 @@ for a quick development setup. Even if somebody wanted to override some of the r
in e.g. your default development setup, they can of course still do that, e.g. by calling
`register()` again to override components as needed.

### Consumption
### Fallback Containers

You can use this feature to build layered architecture with different component life-cycles.

Note that this type of architecture is less about reuse (which in most cases could be
achieved more simply by just reusing providers) and more about separating dependencies
into architectural layers.

The most common use-case for this feature is in long-running "deamons", such as web-hosts,
where this feature can be used to achieve separation of short-lived, request-specific
components from long-lived services. For example, controllers or session-models might be
registered in containers that get created and disposed with each request - while a database
connection or an SMTP client might be registered in a single fallback container that exists
for as long as the application is running, eliminating redundant start-up overhead.

This kind of separation is also useful in terms of architecture, where it forces you to be
deliberate and aware of dependencies on request-specific components, since these will not
be available in the long-lived container. Similarly, maybe your project has a console-based
front-end as well, where this type of architecture can be used to ensure your command-line
dependencies are not available to the components of your web-host - and so on.

In practical terms, to register a fallback container, use the `registerFallback` method on
a `ContainerFactory` instance. Containers created by a factory with one or more registered
fallbacks, will internally query fallbacks (in the order they were added) for any components
that haven't been registered in the container itself - effectively, this means that calls
to `has` and `get` will propagate to any registered fallback containers.

A typical approach is to register the container factory for short-lived services as a component
in the long-lived main service container - for example:

```php
$app_factory = new ContainerFactory();

// components we can reuse across many requests:

$app_factory->register(DatabaseConnection::class);

// factory for containers for individual requests:

$app_factory->register("request-context", function (ContainerInterface $app_container) {
$request_container_factory = new ContainerFactory();

// enable request-specific containers to look up long-lived services in the main container:

$request_container_factory->registerFallback($app_container);

return $request_container_factory;
});

// we can now register short-lived components against the `request-context` container factory:

$app_factory->configure("request-context", function (ContainerFactory $request_container_factory) {
$request_container_factory->register(LoginController::class); // depends on DatabaseConnection
});

// now create the long-lived app container, e.g. in your "index.php" or CLI daemon script:

$app_container = $app_factory->createContainer();
```

With this bootstrapping in place, you can now create instances of the `request-context` container
as needed, e.g. in a long-lived component that handles incoming web-requests:

Consuming the contents of a container by simply pulling components out of it can *seem* very convenient, and is therefore
```php
$request_container = $app_container->get("request-context")->createContainer();

$controller = $request_container->get(LoginController::class);
```

When the `$request_container` falls out of scope, any short-lived components such as the `LoginController`
will be released along with the container - while any long-lived components such as `DatabaseConnection`
will remain in the `$app_container`, with the same instance being passed to every new instance of the
controller.

### Using Containers

Obtaining the contents of a container by simply pulling components out of it can *seem* very convenient, and is therefore
tempting - but usually wrong! You should [inform yourself](http://stackoverflow.com/questions/11316688/inversion-of-control-vs-dependency-injection-with-selected-quotes-is-my-unders/11319026#11319026)
about the difference and **avoid** using the container as a [service locator](https://en.wikipedia.org/wiki/Service_locator_pattern).

Expand Down Expand Up @@ -721,32 +797,30 @@ different qualities - from the smallest and simplest to the largest and most amb
whistles - rich with features, but also has more concepts and learning curve, and more overhead.

The included [simple benchmark](test/benchmark-all.php) generates the following benchmark results on
a Windows 10 system running PHP 5.6.12.
a WSL2 under Windows 10 with PHP 8.0.0.

Time to configure the container:

pimple ........ 0.098 msec ....... 72.31% ......... 1.00x
unbox ......... 0.106 msec ....... 77.98% ......... 1.08x
php-di ........ 0.136 msec ...... 100.00% ......... 1.38x
unbox ......... 0.133 msec ....... 82.21% ......... 1.00x
pimple ........ 0.137 msec ....... 84.55% ......... 1.03x
php-di ........ 0.162 msec ...... 100.00% ......... 1.22x

Time to resolve the dependencies in the container, on first access:

pimple ........ 0.026 msec ....... 10.88% ......... 1.00x
unbox ......... 0.055 msec ....... 23.59% ......... 2.17x
php-di ........ 0.234 msec ...... 100.00% ......... 9.19x
pimple ........ 0.013 msec ....... 15.01% ......... 1.00x
unbox ......... 0.027 msec ....... 30.76% ......... 2.05x
php-di ........ 0.089 msec ...... 100.00% ......... 6.66x

Time for multiple subsequent lookups:

pimple: 3 repeated resolutions ........ 0.028 msec ....... 11.68% ......... 1.00x
unbox: 3 repeated resolutions ......... 0.058 msec ....... 24.04% ......... 2.06x
php-di: 3 repeated resolutions ........ 0.243 msec ...... 100.00% ......... 8.56x

pimple: 5 repeated resolutions ........ 0.028 msec ....... 11.60% ......... 1.00x
unbox: 5 repeated resolutions ......... 0.062 msec ....... 25.64% ......... 2.21x
php-di: 5 repeated resolutions ........ 0.242 msec ...... 100.00% ......... 8.62x

pimple: 10 repeated resolutions ....... 0.040 msec ....... 15.60% ......... 1.00x
unbox: 10 repeated resolutions ........ 0.069 msec ....... 27.02% ......... 1.73x
php-di: 10 repeated resolutions ....... 0.256 msec ...... 100.00% ......... 6.41x

With Unbox, the time needed to resolve a component under PHP 7.x is around 8-10 times less than under PHP 5.6.12.
pimple: 3 repeated resolutions ........ 0.016 msec ....... 18.43% ......... 1.00x
unbox: 3 repeated resolutions ......... 0.030 msec ....... 33.44% ......... 1.81x
php-di: 3 repeated resolutions ........ 0.089 msec ...... 100.00% ......... 5.43x

pimple: 5 repeated resolutions ........ 0.018 msec ....... 19.71% ......... 1.00x
unbox: 5 repeated resolutions ......... 0.035 msec ....... 38.29% ......... 1.94x
php-di: 5 repeated resolutions ........ 0.091 msec ...... 100.00% ......... 5.07x

pimple: 10 repeated resolutions ........ 0.023 msec ....... 24.38% ......... 1.00x
unbox: 10 repeated resolutions ......... 0.033 msec ....... 34.69% ......... 1.42x
php-di: 10 repeated resolutions ........ 0.094 msec ...... 100.00% ......... 4.10x
10 changes: 6 additions & 4 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
Upgrading
=========

#### 3.0.0

This release removes backwards compatibility with the legacy package `container-interop/container-interop`
and legacy interfaces from the `Interop\Container` namespace - the container is now compatible only with
the official, final PSR-11 standard `psr/container` package and interfaces.

#### 2.0.1

This release improves *forward* compatibility with `psr/container`, and backwards compatibility with
the deprecated `container-interop/container-interop` package.

Version 3.0 will most likely remove backwards compatibility with `container-interop/container-interop`,
but as that is a breaking change, this update merely adds forward compatibility with the final PSR-11
package.

#### 2.0.0

Version 2 introduces some BC breaks from version 1.x, as described below.
Expand Down
15 changes: 7 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@
}
],
"require": {
"php": ">=5.5",
"psr/container": "^1.0",
"container-interop/container-interop": "^1.2"
"php": "^7.3 || ^8.0",
"psr/container": "^1.1.1 || ^2.0.0"
},
"require-dev": {
"mindplay/benchpress": "dev-master",
"mindplay/testies": "dev-master",
"phpunit/php-code-coverage": "~2.1",
"php-di/php-di": "^5.0.3",
"pimple/pimple": "3.0.1"
"mindplay/benchpress": "^0.1",
"mindplay/testies": "^1.0",
"php-di/php-di": "^6.3",
"pimple/pimple": "^3.4",
"phpunit/php-code-coverage": "^9.2.5"
},
"autoload": {
"psr-4": {
Expand Down
Loading

0 comments on commit 5a54bb1

Please sign in to comment.