Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve type inference for plugin manager implementations #137

Merged
merged 3 commits into from
Jun 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="4.22.0@fc2c6ab4d5fa5d644d8617089f012f3bb84b8703">
<files psalm-version="4.23.0@f1fe6ff483bf325c803df9f510d09a03fd796f88">
<file src="src/AbstractFactory/ConfigAbstractFactory.php">
<InvalidStringClass occurrences="1">
<code>new $requestedName(...$arguments)</code>
Expand Down Expand Up @@ -405,7 +405,7 @@
<code>$names[$name]</code>
<code>$object[$shared ? $method : 'build']</code>
</MixedArrayOffset>
<MixedAssignment occurrences="26">
<MixedAssignment occurrences="24">
<code>$callSequence</code>
<code>$first</code>
<code>$idx1</code>
Expand Down Expand Up @@ -502,9 +502,6 @@
<MissingClosureParamType occurrences="1">
<code>$autoload</code>
</MissingClosureParamType>
<MixedAssignment occurrences="1">
<code>$instance</code>
</MixedAssignment>
<RedundantConditionGivenDocblockType occurrences="2">
<code>assertIsArray</code>
<code>assertIsArray</code>
Expand Down
14 changes: 11 additions & 3 deletions src/AbstractPluginManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
* The implementation extends `ServiceManager`, thus providing the same set
* of capabilities as found in that implementation.
*
* @template InstanceType of object
* @implements PluginManagerInterface<InstanceType>
* @psalm-import-type ServiceManagerConfiguration from ServiceManager
* @psalm-suppress PropertyNotSetInConstructor
*/
Expand All @@ -48,7 +50,7 @@ abstract class AbstractPluginManager extends ServiceManager implements PluginMan
* An object type that the created instance must be instanced of
*
* @var null|string
* @psalm-var null|class-string
* @psalm-var null|class-string<InstanceType>
*/
protected $instanceOf;

Expand Down Expand Up @@ -131,6 +133,10 @@ public function configure(array $config)
* Override setService for additional plugin validation.
*
* {@inheritDoc}
*
* @param string|class-string<InstanceType> $name
* @param InstanceType $service
* @psalm-suppress MoreSpecificImplementedParamType
*/
public function setService($name, $service)
{
Expand All @@ -139,9 +145,10 @@ public function setService($name, $service)
}

/**
* @param string $name Service name of plugin to retrieve.
* @param class-string<InstanceType>|string $name Service name of plugin to retrieve.
* @param null|array<mixed> $options Options to use when creating the instance.
* @return mixed
* @psalm-return ($name is class-string ? InstanceType : mixed)
* @throws Exception\ServiceNotFoundException If the manager does not have
* a service definition for the instance, and the service is not
* auto-invokable.
Expand All @@ -162,14 +169,15 @@ public function get($name, ?array $options = null)
$this->setFactory($name, Factory\InvokableFactory::class);
}

/** @psalm-suppress MixedAssignment */
$instance = ! $options ? parent::get($name) : $this->build($name, $options);
$this->validate($instance);
return $instance;
}

/**
* {@inheritDoc}
*
* @psalm-assert InstanceType $instance
*/
public function validate($instance)
{
Expand Down
3 changes: 3 additions & 0 deletions src/PluginManagerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
* Interface for a plugin manager
*
* A plugin manager is a specialized service locator used to create homogeneous objects
*
* @template InstanceType of object
*/
interface PluginManagerInterface extends ServiceLocatorInterface
{
Expand All @@ -22,6 +24,7 @@ interface PluginManagerInterface extends ServiceLocatorInterface
* @throws InvalidServiceException If created instance does not respect the
* constraint on type imposed by the plugin manager.
* @throws ContainerExceptionInterface If any other error occurs.
* @psalm-assert InstanceType $instance
*/
public function validate($instance);
}
4 changes: 3 additions & 1 deletion src/ServiceLocatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ interface ServiceLocatorInterface extends ContainerInterface
/**
* Build a service by its name, using optional options (such services are NEVER cached).
*
* @param string $name
* @template T of object
* @param string|class-string<T> $name
* @param null|array<mixed> $options
* @return mixed
* @psalm-return ($name is class-string ? T : mixed)
Ocramius marked this conversation as resolved.
Show resolved Hide resolved
* @throws Exception\ServiceNotFoundException If no factory/abstract
* factory could be found to create the instance.
* @throws Exception\ServiceNotCreatedException If factory/delegator fails
Expand Down
3 changes: 3 additions & 0 deletions src/ServiceManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@ public function build($name, ?array $options = null)

/**
* {@inheritDoc}
*
* @param string|class-string $name
Ocramius marked this conversation as resolved.
Show resolved Hide resolved
* @return bool
*/
public function has($name)
{
Expand Down