Download the PHP package dhii/services without Composer
On this page you can find all versions of the php package dhii/services. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download dhii/services
More information about dhii/services
Files in dhii/services
Package services
Short Description A collection of useful DI service implementations.
License MIT
Informations about the package services
Dhii - Services
This package provides a collection of service factory and extension definition implementations that can be used with PSR-11 containers, as well as the experimental service provider spec, to replace the anonymous functions that are typically used for definitions.
- Requirements
- Installation
- Classes
Factory
Extension
Constructor
ServiceList
ArrayExtension
FuncService
Others
- Mutation
- Multi-Boxing
- Static Analysis
Requirements
- PHP >= 7.0 < PHP 8
Installation
With Composer:
Without Composer:
- Go here.
- Install it.
- See "With Composer"
Classes
All implementations in this package inherit from getDependencies
method that returns an array of keys.
Factory
A simple implementation that uses a callback to construct its service.
Unlike a normal anonymous function, the callback given to the Factory
does not get a ContainerInterface
argument, but rather the services that match the given dependency keys. This allows omitting a lot of trivial service retrieval code, and most importantly type-hinting the services:
Roughly equivalent to:
This is true for all implementations that use a similar mechanic of passing already resolved services to other definitions. Therefore, type-checking code will be henceforth omitted for brevity.
Extension
Very similar to Factory
, but the callback also receives the service instance from the original factory or previous extension as the first argument.
Equivalent to:
Constructor
A variant of Factory
that invokes a constructor, rather than a callback function. Very useful in cases where a class is only constructed using other services.
Equivalent to:
Consequently, it also works without any dependencies, which is useful when the constructor is parameterless:
Equivalent to:
ServiceList
Creates an array that contains the services indicated by its dependencies. Very useful for managing registration of instances when coupled with ArrayExtension
.
Equivalent to:
ArrayExtension
An extension implementation that adds its dependencies to the previous value. Very useful for registering new instances to a list.
Equivalent to:
FuncService
A variant of Factory
, but it returns the callback rather than invoking it. Invocation arguments will be passed before the injected dependencies. Very useful for declaring callback services.
Equivalent to:
Others
StringService
- For services that return strings that are interpolated with other services.Value
- For services that always return a static value.Alias
- An alias for another service, with defaulting capabilities for when the original does not exist.GlobalVar
- For services that return global variables.
Mutation
The withDependencies()
method allows all service instances to be copied with different dependencies, while leaving the original instances unaffected.
This makes it possible to modify service dependencies at run-time, or even during a build process, which can be especially useful when dealing with 3rd party service providers that need to be rewired.
Multi-boxing
One of the benefits of being able to derive new services with different dependencies is the ability to use the same provider multiple times. Let's look at an example.
Consider a service provider for a logger that writes to a file.
Our application needs to keep 2 different log files: one for errors and one for debugging.
Simply using the above service provider twice won't work; we'd be re-declaring the logger
and file_path
services.
Prefixing the factories would allow us to have two instances of the service provider, but that would break the dependencies. If we prefixed the factories from one logger such that they become debug_logger
and debug_file_path
, the debug_logger
factory would still be depending on file_path
, which would no longer exist after prefixing.
This where mutation of dependencies comes in. We can write a PrefixingProvider
decorator that not only prefixes all services in a provider, but also prefixes any dependencies.
(The below class is incomplete for the sake of brevity. Assume that a constructor exists and that it initializes its $prefix
and $provider
properties).
We can now create two different versions of the same service provider:
The first one will provide debug_logger
and debug_file_path
, while the second will provide error_logger
and error_file_path
.
Static Analysis
By having all services declare their dependencies, we open up the possibility to create an inspection tool that statically analyzes a list of services to build a dependency graph. This graph can help uncover various potential problems without needing to run the code. These insights can reveal:
- Circular dependency
- Dependencies that do not exist
- Factories that override each other, rather than using extensions
- Dependency chains that are too deep
- Unused services
No such tool exists at the time of writing, but I do plan on taking on this task.