Commit realizado el 12:13:52 08-04-2024
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* Final class FallbackInstantiator.
|
||||
*
|
||||
* @link https://github.com/googleforcreators/web-stories-wp
|
||||
*
|
||||
* @copyright 2021 Google LLC
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Original code modified for this project.
|
||||
*
|
||||
* @copyright 2021 Google LLC
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Google\Web_Stories\Infrastructure\Injector;
|
||||
|
||||
use Google\Web_Stories\Infrastructure\Instantiator;
|
||||
|
||||
/**
|
||||
* Fallback instantiator to use in case none was provided.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @since 1.6.0
|
||||
*/
|
||||
final class FallbackInstantiator implements Instantiator {
|
||||
|
||||
/**
|
||||
* Make an object instance out of an interface or class.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param class-string $class_name Class to make an object instance out of.
|
||||
* @param array<int, mixed> $dependencies Optional. Dependencies of the class.
|
||||
* @return T Instantiated object.
|
||||
*
|
||||
* @template T
|
||||
*
|
||||
* @phpstan-param class-string<T> $class_name Class to make an object instance out of.
|
||||
*/
|
||||
public function instantiate( string $class_name, array $dependencies = [] ) {
|
||||
return new $class_name( ...$dependencies );
|
||||
}
|
||||
}
|
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/**
|
||||
* Final class InjectionChain.
|
||||
*
|
||||
* @link https://www.mwpd.io/
|
||||
*
|
||||
* @copyright 2019 Alain Schlesser
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Original code modified for this project.
|
||||
*
|
||||
* @copyright 2021 Google LLC
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Google\Web_Stories\Infrastructure\Injector;
|
||||
|
||||
/**
|
||||
* The injection chain is similar to a trace, keeping track of what we have done
|
||||
* so far and at what depth within the auto-wiring we currently are.
|
||||
*
|
||||
* It is used to detect circular dependencies, and can also be dumped for
|
||||
* debugging information.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
final class InjectionChain {
|
||||
|
||||
/**
|
||||
* Chain.
|
||||
*
|
||||
* @var string[]
|
||||
* @phpstan-var class-string<T>[]
|
||||
*/
|
||||
private array $chain = [];
|
||||
|
||||
/**
|
||||
* Resolutions.
|
||||
*
|
||||
* @var array<bool>
|
||||
* @phpstan-var array<class-string, bool>
|
||||
*/
|
||||
private array $resolutions = [];
|
||||
|
||||
/**
|
||||
* Add class to injection chain.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $class_name Class to add to injection chain.
|
||||
* @return self Modified injection chain.
|
||||
*
|
||||
* @phpstan-param class-string<T> $class_name
|
||||
*/
|
||||
public function add_to_chain( string $class_name ): self {
|
||||
$new_chain = clone $this;
|
||||
$new_chain->chain[] = $class_name;
|
||||
|
||||
return $new_chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add resolution for circular reference detection.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $resolution Resolution to add.
|
||||
* @return self Modified injection chain.
|
||||
*
|
||||
* @phpstan-param class-string $resolution
|
||||
*/
|
||||
public function add_resolution( string $resolution ): self {
|
||||
$new_chain = clone $this;
|
||||
$new_chain->resolutions[ $resolution ] = true;
|
||||
|
||||
return $new_chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last class that was pushed to the injection chain.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @throws \LogicException If the injection chain is accessed too early.
|
||||
*
|
||||
* @return string Last class pushed to the injection chain.
|
||||
*
|
||||
* @phpstan-return class-string<T>
|
||||
*/
|
||||
public function get_class(): string {
|
||||
if ( empty( $this->chain ) ) {
|
||||
throw new \LogicException(
|
||||
'Access to injection chain before any resolution was made.'
|
||||
);
|
||||
}
|
||||
|
||||
return \end( $this->chain ) ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the injection chain.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @return string[] Chain of injections.
|
||||
*
|
||||
* @phpstan-return class-string[]
|
||||
*/
|
||||
public function get_chain(): array {
|
||||
return \array_reverse( $this->chain );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the injection chain already has a given resolution.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $resolution Resolution to check for.
|
||||
* @return bool Whether the resolution was found.
|
||||
*
|
||||
* @phpstan-param class-string<T> $resolution
|
||||
*/
|
||||
public function has_resolution( string $resolution ): bool {
|
||||
return \array_key_exists( $resolution, $this->resolutions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the injection chain already encountered a class.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $class_name Class to check.
|
||||
* @return bool Whether the given class is already part of the chain.
|
||||
*/
|
||||
public function is_in_chain( string $class_name ): bool {
|
||||
return \in_array( $class_name, $this->chain, true );
|
||||
}
|
||||
}
|
@@ -0,0 +1,540 @@
|
||||
<?php
|
||||
/**
|
||||
* Final class SimpleInjector.
|
||||
*
|
||||
* @link https://www.mwpd.io/
|
||||
*
|
||||
* @copyright 2019 Alain Schlesser
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Original code modified for this project.
|
||||
*
|
||||
* @copyright 2021 Google LLC
|
||||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Google\Web_Stories\Infrastructure\Injector;
|
||||
|
||||
use Google\Web_Stories\Exception\FailedToMakeInstance;
|
||||
use Google\Web_Stories\Infrastructure\Injector;
|
||||
use Google\Web_Stories\Infrastructure\Instantiator;
|
||||
use ReflectionClass;
|
||||
use ReflectionNamedType;
|
||||
use ReflectionParameter;
|
||||
use function array_map;
|
||||
|
||||
/**
|
||||
* A simplified implementation of a dependency injector.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @template T
|
||||
*/
|
||||
final class SimpleInjector implements Injector {
|
||||
|
||||
/**
|
||||
* Special-case index key for handling globally defined named arguments.
|
||||
*/
|
||||
public const GLOBAL_ARGUMENTS = '__global__';
|
||||
|
||||
/**
|
||||
* Mappings.
|
||||
*
|
||||
* @var string[]
|
||||
* @phpstan-var class-string<T>[]
|
||||
*/
|
||||
private array $mappings = [];
|
||||
|
||||
/**
|
||||
* Shared instances
|
||||
*
|
||||
* @var array<T|null>
|
||||
*/
|
||||
private array $shared_instances = [];
|
||||
|
||||
/**
|
||||
* Delegates.
|
||||
*
|
||||
* @var callable[]
|
||||
*/
|
||||
private array $delegates = [];
|
||||
|
||||
/**
|
||||
* Argument mappings.
|
||||
*
|
||||
* @var array<string, array<mixed>>
|
||||
*/
|
||||
private array $argument_mappings = [
|
||||
self::GLOBAL_ARGUMENTS => [],
|
||||
];
|
||||
|
||||
/**
|
||||
* Instantiator.
|
||||
*
|
||||
* @var Instantiator<T>
|
||||
*/
|
||||
private Instantiator $instantiator;
|
||||
|
||||
/**
|
||||
* Instantiate a SimpleInjector object.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param Instantiator|null $instantiator Optional. Instantiator to use.
|
||||
*/
|
||||
public function __construct( ?Instantiator $instantiator = null ) {
|
||||
$this->instantiator = $instantiator ?? new FallbackInstantiator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an object instance out of an interface or class.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $interface_or_class Interface or class to make an object instance out of.
|
||||
* @param array<string, mixed> $arguments Optional. Additional arguments to pass to the constructor.
|
||||
* Defaults to an empty array.
|
||||
* @return T Instantiated object.
|
||||
*
|
||||
* @phpstan-param class-string<T> $interface_or_class Interface or class to make an object instance out of.
|
||||
* @phpstan-param array<string, mixed> $arguments Optional. Additional arguments to pass to the constructor.
|
||||
*/
|
||||
public function make( string $interface_or_class, array $arguments = [] ) {
|
||||
$injection_chain = $this->resolve(
|
||||
new InjectionChain(),
|
||||
$interface_or_class
|
||||
);
|
||||
|
||||
$class = $injection_chain->get_class();
|
||||
|
||||
if ( $this->has_shared_instance( $class ) ) {
|
||||
return $this->get_shared_instance( $class );
|
||||
}
|
||||
|
||||
if ( $this->has_delegate( $class ) ) {
|
||||
$delegate = $this->get_delegate( $class );
|
||||
$object = $delegate( $class );
|
||||
} else {
|
||||
$reflection = $this->get_class_reflection( $class );
|
||||
$this->ensure_is_instantiable( $reflection );
|
||||
|
||||
$dependencies = $this->get_dependencies_for(
|
||||
$injection_chain,
|
||||
$reflection,
|
||||
$arguments
|
||||
);
|
||||
|
||||
$object = $this->instantiator->instantiate( $class, $dependencies );
|
||||
}
|
||||
|
||||
if ( \array_key_exists( $class, $this->shared_instances ) ) {
|
||||
$this->shared_instances[ $class ] = $object;
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a given interface or class to an implementation.
|
||||
*
|
||||
* Note: The implementation can be an interface as well, as long as it can
|
||||
* be resolved to an instantiatable class at runtime.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $from Interface or class to bind an implementation to.
|
||||
* @param string $to Interface or class that provides the implementation.
|
||||
*
|
||||
* @phpstan-param class-string<T> $from Interface or class to bind an implementation to.
|
||||
* @phpstan-param class-string<T> $to Interface or class that provides the implementation.
|
||||
*/
|
||||
public function bind( string $from, string $to ): Injector {
|
||||
$this->mappings[ $from ] = $to;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind an argument for a class to a specific value.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $interface_or_class Interface or class to bind an argument for.
|
||||
* @param string $argument_name Argument name to bind a value to.
|
||||
* @param mixed $value Value to bind the argument to.
|
||||
*/
|
||||
public function bind_argument(
|
||||
string $interface_or_class,
|
||||
string $argument_name,
|
||||
$value
|
||||
): Injector {
|
||||
$this->argument_mappings[ $interface_or_class ][ $argument_name ] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always reuse and share the same instance for the provided interface or
|
||||
* class.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $interface_or_class Interface or class to reuse.
|
||||
*
|
||||
* @phpstan-param class-string<T> $interface_or_class Interface or class to reuse.
|
||||
*/
|
||||
public function share( string $interface_or_class ): Injector {
|
||||
$this->shared_instances[ $interface_or_class ] = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate instantiation of an interface or class to a callable.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $interface_or_class Interface or class to delegate the instantiation of.
|
||||
* @param callable $callback Callable to use for instantiation.
|
||||
*
|
||||
* @phpstan-param class-string<T> $interface_or_class Interface or class to delegate the instantiation of.
|
||||
*/
|
||||
public function delegate( string $interface_or_class, callable $callback ): Injector {
|
||||
$this->delegates[ $interface_or_class ] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an object instance out of an interface or class.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param InjectionChain $injection_chain Injection chain to track resolutions.
|
||||
* @param string $interface_or_class Interface or class to make an object instance out of.
|
||||
* @return T Instantiated object.
|
||||
*
|
||||
* @phpstan-param class-string<T> $interface_or_class Interface or class to make an object instance out of.
|
||||
*/
|
||||
private function make_dependency(
|
||||
InjectionChain $injection_chain,
|
||||
string $interface_or_class
|
||||
) {
|
||||
$injection_chain = $this->resolve(
|
||||
$injection_chain,
|
||||
$interface_or_class
|
||||
);
|
||||
|
||||
$class = $injection_chain->get_class();
|
||||
|
||||
if ( $this->has_shared_instance( $class ) ) {
|
||||
return $this->get_shared_instance( $class );
|
||||
}
|
||||
|
||||
if ( $this->has_delegate( $class ) ) {
|
||||
$delegate = $this->get_delegate( $class );
|
||||
return $delegate( $class );
|
||||
}
|
||||
|
||||
$reflection = $this->get_class_reflection( $class );
|
||||
$this->ensure_is_instantiable( $reflection );
|
||||
|
||||
$dependencies = $this->get_dependencies_for(
|
||||
$injection_chain,
|
||||
$reflection
|
||||
);
|
||||
|
||||
$object = $this->instantiator->instantiate( $class, $dependencies );
|
||||
|
||||
if ( \array_key_exists( $class, $this->shared_instances ) ) {
|
||||
$this->shared_instances[ $class ] = $object;
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively resolve an interface to the class it should be bound to.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @throws FailedToMakeInstance If a circular reference was detected.
|
||||
*
|
||||
* @param InjectionChain $injection_chain Injection chain to track resolutions.
|
||||
* @param string $interface_or_class Interface or class to resolve.
|
||||
* @return InjectionChain Modified Injection chain
|
||||
*
|
||||
* @phpstan-param class-string<T> $interface_or_class Interface or class to resolve.
|
||||
*/
|
||||
private function resolve(
|
||||
InjectionChain $injection_chain,
|
||||
string $interface_or_class
|
||||
): InjectionChain {
|
||||
if ( $injection_chain->is_in_chain( $interface_or_class ) ) {
|
||||
// Circular reference detected, aborting.
|
||||
throw FailedToMakeInstance::for_circular_reference(
|
||||
$interface_or_class, // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
||||
$injection_chain // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
||||
);
|
||||
}
|
||||
|
||||
$injection_chain = $injection_chain->add_resolution( $interface_or_class );
|
||||
|
||||
if ( \array_key_exists( $interface_or_class, $this->mappings ) ) {
|
||||
return $this->resolve(
|
||||
$injection_chain,
|
||||
$this->mappings[ $interface_or_class ]
|
||||
);
|
||||
}
|
||||
|
||||
return $injection_chain->add_to_chain( $interface_or_class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of constructor dependencies for a given reflected class.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param InjectionChain $injection_chain Injection chain to track resolutions.
|
||||
* @param ReflectionClass $reflection Reflected class to get the dependencies for.
|
||||
* @param array<string, mixed> $arguments Associative array of directly provided arguments.
|
||||
* @return array<int, mixed> Array of dependencies that represent the arguments for the class' constructor.
|
||||
*/
|
||||
private function get_dependencies_for(
|
||||
InjectionChain $injection_chain,
|
||||
ReflectionClass $reflection,
|
||||
array $arguments = []
|
||||
): array {
|
||||
$constructor = $reflection->getConstructor();
|
||||
$class = $reflection->getName();
|
||||
|
||||
if ( null === $constructor ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_map(
|
||||
fn( ReflectionParameter $parameter ) => $this->resolve_argument(
|
||||
$injection_chain,
|
||||
$class,
|
||||
$parameter,
|
||||
$arguments
|
||||
),
|
||||
$constructor->getParameters()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a given reflected class is instantiable.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @throws FailedToMakeInstance If the interface could not be resolved.
|
||||
*
|
||||
* @param ReflectionClass $reflection Reflected class to check.
|
||||
*/
|
||||
private function ensure_is_instantiable( ReflectionClass $reflection ): void {
|
||||
if ( ! $reflection->isInstantiable() ) {
|
||||
throw FailedToMakeInstance::for_unresolved_interface( $reflection->getName() ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a given reflected argument.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param InjectionChain $injection_chain Injection chain to track resolutions.
|
||||
* @param string $class_name Name of the class to resolve the arguments for.
|
||||
* @param ReflectionParameter $parameter Parameter to resolve.
|
||||
* @param array<string, mixed> $arguments Associative array of directly provided arguments.
|
||||
* @return mixed Resolved value of the argument.
|
||||
*/
|
||||
private function resolve_argument(
|
||||
InjectionChain $injection_chain,
|
||||
string $class_name,
|
||||
ReflectionParameter $parameter,
|
||||
array $arguments
|
||||
) {
|
||||
if ( ! $parameter->hasType() ) {
|
||||
return $this->resolve_argument_by_name(
|
||||
$class_name,
|
||||
$parameter,
|
||||
$arguments
|
||||
);
|
||||
}
|
||||
|
||||
$type = $parameter->getType();
|
||||
|
||||
// In PHP 8.0, the isBuiltin method was removed from the parent {@see ReflectionType} class.
|
||||
if ( null === $type || ( $type instanceof ReflectionNamedType && $type->isBuiltin() ) ) {
|
||||
return $this->resolve_argument_by_name(
|
||||
$class_name,
|
||||
$parameter,
|
||||
$arguments
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface or class.
|
||||
*
|
||||
* @var class-string<T> $type
|
||||
*/
|
||||
$type = $type instanceof ReflectionNamedType
|
||||
? $type->getName()
|
||||
: (string) $type;
|
||||
|
||||
return $this->make_dependency( $injection_chain, $type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a given reflected argument by its name.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @throws FailedToMakeInstance If the argument could not be resolved.
|
||||
*
|
||||
* @param string $class_name Class to resolve the argument for.
|
||||
* @param ReflectionParameter $parameter Argument to resolve by name.
|
||||
* @param array<string, mixed> $arguments Associative array of directly provided arguments.
|
||||
* @return mixed Resolved value of the argument.
|
||||
*/
|
||||
private function resolve_argument_by_name(
|
||||
string $class_name,
|
||||
ReflectionParameter $parameter,
|
||||
array $arguments
|
||||
) {
|
||||
$name = $parameter->getName();
|
||||
|
||||
// The argument was directly provided to the make() call.
|
||||
if ( \array_key_exists( $name, $arguments ) ) {
|
||||
return $arguments[ $name ];
|
||||
}
|
||||
|
||||
// Check if we have mapped this argument for the specific class.
|
||||
if ( \array_key_exists( $class_name, $this->argument_mappings )
|
||||
&& \array_key_exists( $name, $this->argument_mappings[ $class_name ] ) ) {
|
||||
$value = $this->argument_mappings[ $class_name ][ $name ];
|
||||
|
||||
// Closures are immediately resolved, to provide lazy resolution.
|
||||
if ( \is_callable( $value ) ) {
|
||||
$value = $value( $class_name, $parameter, $arguments );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
// No argument found for the class, check if we have a global value.
|
||||
if ( \array_key_exists( $name, $this->argument_mappings[ self::GLOBAL_ARGUMENTS ] ) ) {
|
||||
return $this->argument_mappings[ self::GLOBAL_ARGUMENTS ][ $name ];
|
||||
}
|
||||
|
||||
// No provided argument found, check if it has a default value.
|
||||
try {
|
||||
if ( $parameter->isDefaultValueAvailable() ) {
|
||||
return $parameter->getDefaultValue();
|
||||
}
|
||||
} catch ( \Exception $exception ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
// Just fall through into the FailedToMakeInstance exception.
|
||||
}
|
||||
|
||||
// Out of options, fail with an exception.
|
||||
throw FailedToMakeInstance::for_unresolved_argument( $name, $class_name ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a shared instance exists for a given class.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $class_name Class to check for a shared instance.
|
||||
* @return bool Whether a shared instance exists.
|
||||
*/
|
||||
private function has_shared_instance( string $class_name ): bool {
|
||||
return \array_key_exists( $class_name, $this->shared_instances )
|
||||
&& null !== $this->shared_instances[ $class_name ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shared instance for a given class.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @throws FailedToMakeInstance If an uninstantiated shared instance is requested.
|
||||
*
|
||||
* @param string $class_name Class to get the shared instance for.
|
||||
* @return T Shared instance.
|
||||
*
|
||||
* @phpstan-param class-string<T> $class_name Class to get the shared instance for.
|
||||
* @phpstan-return T Shared instance.
|
||||
*/
|
||||
private function get_shared_instance( string $class_name ) {
|
||||
if ( ! $this->has_shared_instance( $class_name ) ) {
|
||||
throw FailedToMakeInstance::for_uninstantiated_shared_instance( $class_name ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shared instance.
|
||||
*
|
||||
* @var T $instance
|
||||
*/
|
||||
$instance = $this->shared_instances[ $class_name ];
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a delegate exists for a given class.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param string $class_name Class to check for a delegate.
|
||||
* @return bool Whether a delegate exists.
|
||||
*/
|
||||
private function has_delegate( string $class_name ): bool {
|
||||
return \array_key_exists( $class_name, $this->delegates );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the delegate for a given class.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @throws FailedToMakeInstance If an invalid delegate is requested.
|
||||
*
|
||||
* @param string $class_name Class to get the delegate for.
|
||||
* @return callable Delegate.
|
||||
*/
|
||||
private function get_delegate( string $class_name ): callable {
|
||||
if ( ! $this->has_delegate( $class_name ) ) {
|
||||
throw FailedToMakeInstance::for_invalid_delegate( $class_name ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
||||
}
|
||||
|
||||
return $this->delegates[ $class_name ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reflection for a class or throw an exception.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @throws FailedToMakeInstance If the class could not be reflected.
|
||||
*
|
||||
* @param string|class-string $class_name Class to get the reflection for.
|
||||
* @return ReflectionClass Class reflection.
|
||||
*/
|
||||
private function get_class_reflection( string $class_name ): ReflectionClass {
|
||||
if ( ! class_exists( $class_name ) ) {
|
||||
throw FailedToMakeInstance::for_unreflectable_class( $class_name ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
||||
}
|
||||
|
||||
// There should be no ReflectionException happening because of the class existence check above.
|
||||
return new ReflectionClass( $class_name );
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user