芝麻web文件管理V1.00
编辑当前文件:/home2/sdektunc/www/libraries/vendor/joomla/di/src/Container.php
'key' * * @var array * @since 1.0 */ protected $aliases = []; /** * Holds the resources. * * @var ContainerResource[] * @since 2.0.0 */ protected $resources = []; /** * Parent for hierarchical containers. * * In fact, this can be any PSR-11 compatible container, which gets decorated by this * * @var Container|ContainerInterface|null * @since 1.0 */ protected $parent; /** * Holds the service tag mapping. * * @var array * @since 1.5.0 */ protected $tags = []; /** * Constructor for the DI Container * * @param ContainerInterface|null $parent Parent for hierarchical containers. * * @since 1.0 */ public function __construct(?ContainerInterface $parent = null) { $this->parent = $parent; } /** * Retrieve a resource * * @param string $resourceName Name of the resource to get. * * @return mixed The requested resource * * @since 1.0 * @throws KeyNotFoundException */ public function get($resourceName) { $key = $this->resolveAlias($resourceName); if (!isset($this->resources[$key])) { if ($this->parent instanceof ContainerInterface && $this->parent->has($key)) { return $this->parent->get($key); } throw new KeyNotFoundException(sprintf("Resource '%s' has not been registered with the container.", $resourceName)); } return $this->resources[$key]->getInstance(); } /** * Check if specified resource exists. * * @param string $resourceName Name of the resource to check. * * @return boolean true if key is defined, false otherwise * * @since 1.5.0 */ public function has($resourceName) { $key = $this->resolveAlias($resourceName); if (!isset($this->resources[$key])) { if ($this->parent instanceof ContainerInterface) { return $this->parent->has($key); } return false; } return true; } /** * Method to check if specified dataStore key exists. * * @param string $key Name of the dataStore key to check. * * @return boolean True for success * * @since 1.0 * @deprecated 3.0 Use ContainerInterface::has() instead */ public function exists($key) { trigger_deprecation( 'joomla/di', '1.5.0', '%s() is deprecated and will be removed in 3.0, use %s::has() instead.', __METHOD__, ContainerInterface::class ); return $this->has($key); } /** * Create an alias for a given key for easy access. * * @param string $alias The alias name * @param string $key The key to alias * * @return $this * * @since 1.0 */ public function alias($alias, $key) { $this->aliases[$alias] = $key; return $this; } /** * Resolve a resource name. * * If the resource name is an alias, the corresponding key is returned. * If the resource name is not an alias, the resource name is returned unchanged. * * @param string $resourceName The key to search for. * * @return string * * @since 1.0 */ protected function resolveAlias($resourceName) { return $this->aliases[$resourceName] ?? $resourceName; } /** * Check whether a resource is shared * * @param string $resourceName Name of the resource to check. * * @return boolean * * @since 2.0.0 */ public function isShared(string $resourceName): bool { return $this->hasFlag($resourceName, 'isShared', true); } /** * Check whether a resource is protected * * @param string $resourceName Name of the resource to check. * * @return boolean * * @since 2.0.0 */ public function isProtected(string $resourceName): bool { return $this->hasFlag($resourceName, 'isProtected', true); } /** * Check whether a flag (i.e., one of 'shared' or 'protected') is set * * @param string $resourceName Name of the resource to check. * @param string $method Method to delegate to * @param boolean $default Default return value * * @return boolean * * @since 2.0.0 * @throws KeyNotFoundException */ private function hasFlag(string $resourceName, string $method, bool $default = true): bool { $key = $this->resolveAlias($resourceName); if (isset($this->resources[$key])) { return \call_user_func([$this->resources[$key], $method]); } if ($this->parent instanceof self) { return \call_user_func([$this->parent, $method], $key); } if ($this->parent instanceof ContainerInterface && $this->parent->has($key)) { // We don't know if the parent supports the 'shared' or 'protected' concept, so we assume the default return $default; } throw new KeyNotFoundException(sprintf("Resource '%s' has not been registered with the container.", $resourceName)); } /** * Assign a tag to services. * * @param string $tag The tag name * @param array $keys The service keys to tag * * @return $this * * @since 1.5.0 */ public function tag($tag, array $keys) { foreach ($keys as $key) { $resolvedKey = $this->resolveAlias($key); if (!isset($this->tags[$tag])) { $this->tags[$tag] = []; } $this->tags[$tag][] = $resolvedKey; } // Prune duplicates $this->tags[$tag] = array_unique($this->tags[$tag]); return $this; } /** * Fetch all services registered to the given tag. * * @param string $tag The tag name * * @return array The resolved services for the given tag * * @since 1.5.0 */ public function getTagged($tag) { $services = []; if (isset($this->tags[$tag])) { foreach ($this->tags[$tag] as $service) { $services[] = $this->get($service); } } return $services; } /** * Build an object of the requested class * * Creates an instance of the class specified by $resourceName with all dependencies injected. * If the dependencies cannot be completely resolved, a DependencyResolutionException is thrown. * * @param string $resourceName The class name to build. * @param boolean $shared True to create a shared resource. * * @return object|false Instance of class specified by $resourceName with all dependencies injected. * Returns an object if the class exists and false otherwise * * @since 1.0 * @throws DependencyResolutionException if the object could not be built (due to missing information) */ public function buildObject($resourceName, $shared = false) { static $buildStack = []; $key = $this->resolveAlias($resourceName); if (\in_array($key, $buildStack, true)) { $buildStack = []; throw new DependencyResolutionException(sprintf('Cannot resolve circular dependency for "%s"', $key)); } $buildStack[] = $key; if ($this->has($key)) { $resource = $this->get($key); array_pop($buildStack); return $resource; } try { $reflection = new \ReflectionClass($key); } catch (\ReflectionException $e) { array_pop($buildStack); return false; } if (!$reflection->isInstantiable()) { $buildStack = []; if ($reflection->isInterface()) { throw new DependencyResolutionException( sprintf('There is no service for "%s" defined, cannot autowire a class service for an interface.', $key) ); } if ($reflection->isAbstract()) { throw new DependencyResolutionException( sprintf('There is no service for "%s" defined, cannot autowire an abstract class.', $key) ); } throw new DependencyResolutionException(sprintf('"%s" cannot be instantiated.', $key)); } $constructor = $reflection->getConstructor(); // If there are no parameters, just return a new object. if ($constructor === null) { // There is no constructor, just return a new object. $callback = function () use ($key) { return new $key; }; } else { $newInstanceArgs = $this->getMethodArgs($constructor); $callback = function () use ($reflection, $newInstanceArgs) { return $reflection->newInstanceArgs($newInstanceArgs); }; } $this->set($key, $callback, $shared); $resource = $this->get($key); array_pop($buildStack); return $resource; } /** * Convenience method for building a shared object. * * @param string $resourceName The class name to build. * * @return object|false Instance of class specified by $resourceName with all dependencies injected. * Returns an object if the class exists and false otherwise * * @since 1.0 */ public function buildSharedObject($resourceName) { return $this->buildObject($resourceName, true); } /** * Create a child Container with a new property scope that has the ability to access the parent scope when resolving. * * @return Container A new container with the current as a parent * * @since 1.0 */ public function createChild() { return new static($this); } /** * Extend a defined service Closure by wrapping the existing one with a new callable function. * * This works very similar to a decorator pattern. Note that this only works on service Closures * that have been defined in the current container, not parent containers. * * @param string $resourceName The unique identifier for the Closure or property. * @param callable $callable A callable to wrap the original service Closure. * * @return void * * @since 1.0 * @throws KeyNotFoundException */ public function extend($resourceName, callable $callable) { $key = $this->resolveAlias($resourceName); $resource = $this->getResource($key, true); $closure = function ($c) use ($callable, $resource) { return $callable($resource->getInstance(), $c); }; $this->set($key, $closure, $resource->isShared()); } /** * Build an array of method arguments. * * @param \ReflectionMethod $method Method for which to build the argument array. * * @return array Array of arguments to pass to the method. * * @since 1.0 * @throws DependencyResolutionException */ private function getMethodArgs(\ReflectionMethod $method): array { $methodArgs = []; foreach ($method->getParameters() as $param) { // Check for a typehinted dependency if ($param->hasType()) { $dependency = $param->getType(); // Don't support PHP 8 union types if ($dependency instanceof \ReflectionUnionType) { // If this is a nullable parameter, then don't error out if ($param->allowsNull()) { $methodArgs[] = null; continue; } throw new DependencyResolutionException( sprintf( 'Could not resolve the parameter "$%s" of "%s::%s()": Union typehints are not supported.', $param->name, $method->class, $method->name ) ); } // Check for a class, if it doesn't have one then it is a scalar type, which we cannot handle if a mandatory argument if ($dependency->isBuiltin()) { // If the param is optional, then fall through to the optional param handling later in this method if (!$param->isOptional()) { $message = 'Could not resolve the parameter "$%s" of "%s::%s()":'; $message .= ' Scalar parameters cannot be autowired and the parameter does not have a default value.'; throw new DependencyResolutionException( sprintf( $message, $param->name, $method->class, $method->name ) ); } } else { $dependencyClassName = $dependency->getName(); // Check that class or interface exists if (!interface_exists($dependencyClassName) && !class_exists($dependencyClassName)) { // If this is a nullable parameter, then don't error out if ($param->allowsNull()) { $methodArgs[] = null; continue; } throw new DependencyResolutionException( sprintf( 'Could not resolve the parameter "$%s" of "%s::%s()": The "%s" class does not exist.', $param->name, $method->class, $method->name, $dependencyClassName ) ); } // If the dependency class name is registered with this container or a parent, use it. if ($this->getResource($dependencyClassName) !== null) { $depObject = $this->get($dependencyClassName); } else { try { $depObject = $this->buildObject($dependencyClassName); } catch (DependencyResolutionException $exception) { // If this is a nullable parameter, then don't error out if ($param->allowsNull()) { $methodArgs[] = null; continue; } $message = 'Could not resolve the parameter "$%s" of "%s::%s()":'; $message .= ' No service for "%s" exists and the dependency could not be autowired.'; throw new DependencyResolutionException( sprintf( $message, $param->name, $method->class, $method->name, $dependencyClassName ), 0, $exception ); } } if ($depObject instanceof $dependencyClassName) { $methodArgs[] = $depObject; continue; } } } // If there is a default parameter and it can be read, use it. if ($param->isOptional() && $param->isDefaultValueAvailable()) { try { $methodArgs[] = $param->getDefaultValue(); continue; } catch (\ReflectionException $exception) { throw new DependencyResolutionException( sprintf( 'Could not resolve the parameter "$%s" of "%s::%s()": Unable to read the default parameter value.', $param->name, $method->class, $method->name ), 0, $exception ); } } // If an untyped variadic argument, skip it if (!$param->hasType() && $param->isVariadic()) { continue; } // At this point the argument cannot be resolved, most likely cause is an untyped required argument throw new DependencyResolutionException( sprintf( 'Could not resolve the parameter "$%s" of "%s::%s()": The argument is untyped and has no default value.', $param->name, $method->class, $method->name ) ); } return $methodArgs; } /** * Set a resource to the container. If the value is null the resource is removed. * * @param string $key Name of resources key to set. * @param mixed $value Callable function to run or string to retrive when requesting the specified $key. * @param boolean $shared True to create and store a shared instance. * @param boolean $protected True to protect this item from being overwritten. Useful for services. * * @return $this * * @since 1.0 * @throws ProtectedKeyException Thrown if the provided key is already set and is protected. */ public function set($key, $value, $shared = false, $protected = false) { $key = $this->resolveAlias($key); $hasKey = $this->has($key); if ($hasKey && $this->isProtected($key)) { throw new ProtectedKeyException(sprintf("Key %s is protected and can't be overwritten.", $key)); } if ($value === null && $hasKey) { unset($this->resources[$key]); return $this; } $mode = $shared ? ContainerResource::SHARE : ContainerResource::NO_SHARE; $mode |= $protected ? ContainerResource::PROTECT : ContainerResource::NO_PROTECT; $this->resources[$key] = new ContainerResource($this, $value, $mode); return $this; } /** * Shortcut method for creating protected keys. * * @param string $key Name of dataStore key to set. * @param mixed $value Callable function to run or string to retrive when requesting the specified $key. * @param boolean $shared True to create and store a shared instance. * * @return $this * * @since 1.0 */ public function protect($key, $value, $shared = false) { return $this->set($key, $value, $shared, true); } /** * Shortcut method for creating shared keys. * * @param string $key Name of dataStore key to set. * @param mixed $value Callable function to run or string to retrive when requesting the specified $key. * @param boolean $protected True to protect this item from being overwritten. Useful for services. * * @return $this * * @since 1.0 */ public function share($key, $value, $protected = false) { return $this->set($key, $value, true, $protected); } /** * Get the raw data assigned to a key. * * @param string $key The key for which to get the stored item. * @param boolean $bail Throw an exception, if the key is not found * * @return ContainerResource|null The resource if present, or null if instructed to not bail * * @since 2.0.0 * @throws KeyNotFoundException */ public function getResource(string $key, bool $bail = false): ?ContainerResource { if (isset($this->resources[$key])) { return $this->resources[$key]; } if ($this->parent instanceof self) { return $this->parent->getResource($key); } if ($this->parent instanceof ContainerInterface && $this->parent->has($key)) { return new ContainerResource($this, $this->parent->get($key), ContainerResource::SHARE | ContainerResource::PROTECT); } if ($bail) { throw new KeyNotFoundException(sprintf('Key %s has not been registered with the container.', $key)); } return null; } /** * Method to force the container to return a new instance of the results of the callback for requested $key. * * @param string $key Name of the resources key to get. * * @return mixed Results of running the callback for the specified key. * * @since 1.0 */ public function getNewInstance($key) { $key = $this->resolveAlias($key); $this->getResource($key, true)->reset(); return $this->get($key); } /** * Register a service provider to the container. * * @param ServiceProviderInterface $provider The service provider to register. * * @return $this * * @since 1.0 */ public function registerServiceProvider(ServiceProviderInterface $provider) { $provider->register($this); return $this; } /** * Retrieve the keys for services assigned to this container. * * @return array * * @since 1.5.0 */ public function getKeys() { return array_unique(array_merge(array_keys($this->aliases), array_keys($this->resources))); } }