Skip to content

Commit

Permalink
Merge pull request #2 from defunctl/feature/generics
Browse files Browse the repository at this point in the history
First pass at adding generics
  • Loading branch information
defunctl authored Aug 31, 2023
2 parents a86c6d3 + 7f9fbf2 commit c21e6b7
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 163 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ to [Semantic Versioning](http://semver.org/).

## [unreleased] Unreleased

### Changed

- Added [PHPStan generics](https://phpstan.org/blog/generics-in-php-using-phpdocs) to multiple classes. IDEs that support them will get autocompletion (.phpstorm.meta.php not required) if a fully-qualified class name is used, e.g. `$instance = $container->get( Test::class );`.

## [3.3.4] 2023-06-20;

### Added
Expand Down
121 changes: 64 additions & 57 deletions src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,14 @@ public static function offsetSet($offset, $value)
/**
* Binds an interface a class or a string slug to an implementation and will always return the same instance.
*
* @param string $id A class or interface fully qualified name or a string slug.
* @param mixed $implementation The implementation that should be bound to the alias(es); can be a
* class name, an object or a closure.
* @param array<string>|null $afterBuildMethods An array of methods that should be called on the built
* implementation after resolving it.
* @param string|class-string $id A class or interface fully qualified name or a string slug.
* @param mixed $implementation The implementation that should be bound to the alias(es); can
* be a class name, an object or a closure.
* @param string[]|null $afterBuildMethods An array of methods that should be called on the built
* implementation after resolving it.
*
* @return void This method does not return any value.
*
* @throws ContainerException If there's any issue reflecting on the class, interface or the implementation.
*/
public static function singleton($id, $implementation = null, array $afterBuildMethods = null)
Expand Down Expand Up @@ -124,11 +125,12 @@ public static function getVar($key, $default = null)
/**
* Finds an entry of the container by its identifier and returns it.
*
* @param string $offset Identifier of the entry to look for.
* @template T
*
* @return mixed The entry for an id.
* @param string|class-string<T> $offset Identifier of the entry to look for.
*
* @return mixed The value for the offset.
* @return T|mixed The value for the offset.
* @phpstan-return ($offset is class-string ? T : mixed)
*
* @throws ContainerException Error while retrieving the entry.
* @throws NotFoundException No entry was found for **this** identifier.
Expand All @@ -141,9 +143,12 @@ public static function offsetGet($offset)
/**
* Finds an entry of the container by its identifier and returns it.
*
* @param string $id A fully qualified class or interface name or an already built object.
* @template T
*
* @param string|class-string<T> $id A fully qualified class or interface name or an already built object.
*
* @return mixed The entry for an id.
* @return T|mixed The entry for an id.
* @phpstan-return ($id is class-string ? T : mixed)
*
* @throws ContainerException Error while retrieving the entry.
*/
Expand All @@ -159,9 +164,13 @@ public static function get($id)
* If the implementation has been bound as singleton using the `singleton` method
* or the ArrayAccess API then the implementation will be resolved just on the first request.
*
* @param string $id A fully qualified class or interface name or an already built object.
* @template T
*
* @param string|class-string<T> $id A fully qualified class or interface name or an already built object.
*
* @return T|mixed
* @phpstan-return ($id is class-string ? T : mixed)
*
* @return mixed
* @throws ContainerException If the target of the make is not bound and is not a valid,
* concrete, class name or there's any issue making the target.
*/
Expand All @@ -177,7 +186,7 @@ public static function make($id)
* `$container[$id]` returning true does not mean that `$container[$id]` will not throw an exception.
* It does however mean that `$container[$id]` will not throw a `NotFoundExceptionInterface`.
*
* @param string $offset An offset to check for.
* @param string|class-string $offset An offset to check for.
*
* @return boolean true on success or false on failure.
*/
Expand All @@ -193,7 +202,7 @@ public static function offsetExists($offset)
* `has($id)` returning true does not mean that `get($id)` will not throw an exception.
* It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
*
* @param string $id Identifier of the entry to look for.
* @param string|class-string $id Identifier of the entry to look for.
*
* @return bool Whether the container contains a binding for an id or not.
*/
Expand Down Expand Up @@ -271,7 +280,7 @@ public static function hasTag($tag)
* If a provider overloads the `boot` method that method will be called when the `boot` method is called on the
* container itself.
*
* @param string $serviceProviderClass The fully-qualified Service Provider class name.
* @param class-string $serviceProviderClass The fully-qualified Service Provider class name.
* @param string ...$alias A list of aliases the provider should be registered with.
* @return void This method does not return any value.
* @throws ContainerException If the Service Provider is not correctly configured or there's an issue
Expand All @@ -292,13 +301,14 @@ public static function register($serviceProviderClass, ...$alias)
*
* Existing implementations are replaced.
*
* @param string $id A class or interface fully qualified name or a string slug.
* @param mixed $implementation The implementation that should be bound to the alias(es); can be a
* class name, an object or a closure.
* @param array<string>|null $afterBuildMethods An array of methods that should be called on the built
* implementation after resolving it.
* @param string|class-string $id A class or interface fully qualified name or a string slug.
* @param mixed $implementation The implementation that should be bound to the alias(es); can
* be a class name, an object or a closure.
* @param string[]|null $afterBuildMethods An array of methods that should be called on the built
* implementation after resolving it.
*
* @return void The method does not return any value.
*
* @throws ContainerException If there's an issue while trying to bind the implementation.
*/
public static function bind($id, $implementation = null, array $afterBuildMethods = null)
Expand All @@ -324,15 +334,14 @@ public static function boot()
/**
* Binds a class, interface or string slug to a chain of implementations decorating a base
* object; the chain will be lazily resolved only on the first call.
*
* The base decorated object must be the last element of the array.
*
* @param string $id The class, interface or slug the decorator chain should
* be bound to.
* @param array<string|object|callable> $decorators An array of implementations that decorate an object.
* @param array<string>|null $afterBuildMethods An array of methods that should be called on the
* instance after it has been built; the methods should not
* require any argument.
* @param string|class-string $id The class, interface or slug the decorator chain
* should be bound to.
* @param array<string|object|callable> $decorators An array of implementations that decorate an object.
* @param string[]|null $afterBuildMethods An array of methods that should be called on the
* instance after it has been built; the methods should
* not require any argument.
*
* @return void This method does not return any value.
* @throws ContainerException
Expand All @@ -343,17 +352,17 @@ public static function singletonDecorators($id, $decorators, array $afterBuildMe
}

/**
* Binds a class, interface or string slug to to a chain of implementations decorating a
* Binds a class, interface or string slug to a chain of implementations decorating a
* base object.
*
* The base decorated object must be the last element of the array.
*
* @param string $id The class, interface or slug the decorator chain should
* be bound to.
* @param array<string|object|callable> $decorators An array of implementations that decorate an object.
* @param array<string>|null $afterBuildMethods An array of methods that should be called on the
* instance after it has been built; the methods should not
* require any argument.
* @param string|class-string $id The class, interface or slug the decorator chain
* should be bound to.
* @param array<string|object|callable> $decorators An array of implementations that decorate an object.
* @param string[]|null $afterBuildMethods An array of methods that should be called on the
* instance after it has been built; the methods should
* not require any argument.
*
* @return void This method does not return any value.
* @throws ContainerException If there's any issue binding the decorators.
Expand All @@ -378,16 +387,16 @@ public static function offsetUnset($offset)
/**
* Starts the `when->needs->give` chain for a contextual binding.
*
* @param string $class The fully qualified name of the requesting class.
* @param string|class-string $class The fully qualified name of the requesting class.
*
* Example:
*
* // Any class requesting an implementation of `LoggerInterface` will receive this implementation ...
* $container->singleton('LoggerInterface', 'FilesystemLogger');
* // But if the requesting class is `Worker` return another implementation
* $container->when('Worker')
* ->needs('LoggerInterface)
* ->give('RemoteLogger);
* ->needs('LoggerInterface')
* ->give('RemoteLogger');
*
* @return Container The container instance, to continue the when/needs/give chain.
*/
Expand All @@ -405,10 +414,10 @@ public static function when($class)
* $container->singleton('LoggerInterface', 'FilesystemLogger');
* // But if the requesting class is `Worker` return another implementation.
* $container->when('Worker')
* ->needs('LoggerInterface)
* ->give('RemoteLogger);
* ->needs('LoggerInterface')
* ->give('RemoteLogger');
*
* @param string $id The class or interface needed by the class.
* @param string|class-string $id The class or interface needed by the class.
*
* @return Container The container instance, to continue the when/needs/give chain.
*/
Expand All @@ -426,8 +435,8 @@ public static function needs($id)
* $container->singleton('LoggerInterface', 'FilesystemLogger');
* // but if the requesting class is `Worker` return another implementation
* $container->when('Worker')
* ->needs('LoggerInterface)
* ->give('RemoteLogger);
* ->needs('LoggerInterface')
* ->give('RemoteLogger');
*
* @param mixed $implementation The implementation specified
*
Expand All @@ -443,13 +452,12 @@ public static function give($implementation)
* Returns a lambda function suitable to use as a callback; when called the function will build the implementation
* bound to `$id` and return the value of a call to `$method` method with the call arguments.
*
* @param string|object $id A fully-qualified class name, a bound slug or an object o call the
* callback on.
* @param string $method The method that should be called on the resolved implementation with the
* specified array arguments.
* @param string|class-string|object $id A fully-qualified class name, a bound slug or an object o call the
* callback on.
* @param string $method The method that should be called on the resolved implementation
* with the specified array arguments.
*
* @return callable The callback function.
*
* @throws ContainerException If the id is not a bound implementation or valid class name.
*/
public static function callback($id, $method)
Expand All @@ -460,15 +468,14 @@ public static function callback($id, $method)
/**
* Returns a callable object that will build an instance of the specified class using the
* specified arguments when called.
*
* The callable will be a closure on PHP 5.3+ or a lambda function on PHP 5.2.
*
* @param string|mixed $id The fully qualified name of a class or an interface.
* @param array<mixed> $buildArgs An array of arguments that should be used to build the instance;
* note that any argument will be resolved using the container itself
* and bindings will apply.
* @param array<string>|null $afterBuildMethods An array of methods that should be called on the built
* implementation after resolving it.
* @param string|class-string|mixed $id The fully qualified name of a class or an interface.
* @param array<mixed> $buildArgs An array of arguments that should be used to build the
* instance; note that any argument will be resolved using
* the container itself and bindings will apply.
* @param string[]|null $afterBuildMethods An array of methods that should be called on the built
* implementation after resolving it.
*
* @return callable A callable function that will return an instance of the specified class when
* called.
Expand All @@ -493,7 +500,7 @@ public static function protect($value)
/**
* Returns the Service Provider instance registered.
*
* @param string $providerId The Service Provider clas to return the instance for.
* @param string|class-string $providerId The Service Provider class to return the instance for.
*
* @return ServiceProvider The service provider instance.
*
Expand All @@ -508,10 +515,10 @@ public static function getProvider($providerId)
/**
* Returns whether a binding exists in the container or not.
*
* `isBound($id)` returning `true` means the a call to `bind($id, $implementaion)` or `singleton($id,
* `isBound($id)` returning `true` means the call to `bind($id, $implementaion)` or `singleton($id,
* $implementation)` (or equivalent ArrayAccess methods) was explicitly made.
*
* @param string $id The id to check for bindings in the container.
* @param string|class-string $id The id to check for bindings in the container.
*
* @return bool Whether an explicit binding for the id exists in the container or not.
*/
Expand Down
17 changes: 9 additions & 8 deletions src/Builders/ClassBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ClassBuilder implements BuilderInterface, ReinitializableBuilderInterface
/**
* The fully-qualified class name the builder should build instances of.
*
* @var string
* @var class-string
*/
protected $className;
/**
Expand Down Expand Up @@ -65,12 +65,12 @@ class ClassBuilder implements BuilderInterface, ReinitializableBuilderInterface
/**
* ClassBuilder constructor.
*
* @param string $id The identifier associated with this builder.
* @param Resolver $resolver A reference to the resolver currently using the builder.
* @param string $className The fully-qualified class name to build instances for.
* @param array<string>|null $afterBuildMethods An optional set of methods to call on the built object.
* @param mixed ...$buildArgs An optional set of build arguments that should be provided to the
* class constructor method.
* @param string|class-string $id The identifier associated with this builder.
* @param Resolver $resolver A reference to the resolver currently using the builder.
* @param string $className The fully-qualified class name to build instances for.
* @param string[]|null $afterBuildMethods An optional set of methods to call on the built object.
* @param mixed ...$buildArgs An optional set of build arguments that should be provided to
* the class constructor method.
*
* @throws NotFoundException If the class does not exist.
*/
Expand Down Expand Up @@ -145,7 +145,8 @@ protected function resolveConstructorParameters()
/**
* Returns a set of resolved constructor parameters.
*
* @param string $className The fully-qualified class name to get the resolved constructor parameters yet.
* @param class-string $className The fully-qualified class name to get the resolved constructor parameters yet.
*
* @return array<Parameter> A set of resolved constructor parameters.
*
* @throws ContainerException If the resolution of any constructor parameters is problematic.
Expand Down
Loading

0 comments on commit c21e6b7

Please sign in to comment.