HEX
Server: Apache/2.4.41 (Ubuntu)
System: Linux ip-172-31-42-149 5.15.0-1084-aws #91~20.04.1-Ubuntu SMP Fri May 2 07:00:04 UTC 2025 aarch64
User: ubuntu (1000)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/vhost/disk-apps/magento.bikenow.co/vendor/laminas/laminas-di/src/InstanceManager.php
<?php

/**
 * @see       https://github.com/laminas/laminas-di for the canonical source repository
 * @copyright https://github.com/laminas/laminas-di/blob/master/COPYRIGHT.md
 * @license   https://github.com/laminas/laminas-di/blob/master/LICENSE.md New BSD License
 */

namespace Laminas\Di;

/**
 * Registry of instantiated objects, their names and the parameters used to build them
 */
class InstanceManager /* implements InstanceManagerInterface */
{
    /**
     * Array of shared instances
     * @var array
     */
    protected $sharedInstances = [];

    /**
     * Array of shared instances with params
     * @var array
     */
    protected $sharedInstancesWithParams = ['hashShort' => [], 'hashLong' => []];

    /**
     * Array of class aliases
     * @var array key: alias, value: class
     */
    protected $aliases = [];

    /**
     * The template to use for housing configuration information
     * @var array
     */
    protected $configurationTemplate = [
        /**
         * alias|class => alias|class
         * interface|abstract => alias|class|object
         * name => value
         */
        'parameters' => [],
        /**
         * injection type => array of ordered method params
         */
        'injections' => [],
        /**
         * alias|class => bool
         */
        'shared' => true
    ];

    /**
     * An array of instance configuration data
     * @var array
     */
    protected $configurations = [];

    /**
     * An array of globally preferred implementations for interfaces/abstracts
     * @var array
     */
    protected $typePreferences = [];

    /**
     * Does this instance manager have this shared instance
     * @param  string $classOrAlias
     * @return bool
     */
    public function hasSharedInstance($classOrAlias)
    {
        return isset($this->sharedInstances[$classOrAlias]);
    }

    /**
     * getSharedInstance()
     */
    public function getSharedInstance($classOrAlias)
    {
        return $this->sharedInstances[$classOrAlias];
    }

    /**
     * Add shared instance
     *
     * @param  object                             $instance
     * @param  string                             $classOrAlias
     * @throws Exception\InvalidArgumentException
     */
    public function addSharedInstance($instance, $classOrAlias)
    {
        if (!is_object($instance)) {
            throw new Exception\InvalidArgumentException('This method requires an object to be shared. Class or Alias given: ' . $classOrAlias);
        }

        $this->sharedInstances[$classOrAlias] = $instance;
    }

    /**
     * hasSharedInstanceWithParameters()
     *
     * @param  string      $classOrAlias
     * @param  array       $params
     * @param  bool        $returnFastHashLookupKey
     * @return bool|string
     */
    public function hasSharedInstanceWithParameters($classOrAlias, array $params, $returnFastHashLookupKey = false)
    {
        ksort($params);
        $hashKey = $this->createHashForKeys($classOrAlias, array_keys($params));
        if (isset($this->sharedInstancesWithParams['hashShort'][$hashKey])) {
            $hashValue = $this->createHashForValues($classOrAlias, $params);
            if (isset($this->sharedInstancesWithParams['hashLong'][$hashKey . '/' . $hashValue])) {
                return ($returnFastHashLookupKey) ? $hashKey . '/' . $hashValue : true;
            }
        }

        return false;
    }

    /**
     * addSharedInstanceWithParameters()
     *
     * @param  object $instance
     * @param  string $classOrAlias
     * @param  array  $params
     * @return void
     */
    public function addSharedInstanceWithParameters($instance, $classOrAlias, array $params)
    {
        ksort($params);
        $hashKey = $this->createHashForKeys($classOrAlias, array_keys($params));
        $hashValue = $this->createHashForValues($classOrAlias, $params);

        if (!isset($this->sharedInstancesWithParams[$hashKey])
            || !is_array($this->sharedInstancesWithParams[$hashKey])) {
            $this->sharedInstancesWithParams[$hashKey] = [];
        }

        $this->sharedInstancesWithParams['hashShort'][$hashKey] = true;
        $this->sharedInstancesWithParams['hashLong'][$hashKey . '/' . $hashValue] = $instance;
    }

    /**
     * Retrieves an instance by its name and the parameters stored at its instantiation
     *
     * @param  string      $classOrAlias
     * @param  array       $params
     * @param  bool|null   $fastHashFromHasLookup
     * @return object|bool false if no instance was found
     */
    public function getSharedInstanceWithParameters($classOrAlias, array $params, $fastHashFromHasLookup = null)
    {
        if ($fastHashFromHasLookup) {
            return $this->sharedInstancesWithParams['hashLong'][$fastHashFromHasLookup];
        }

        ksort($params);
        $hashKey = $this->createHashForKeys($classOrAlias, array_keys($params));
        if (isset($this->sharedInstancesWithParams['hashShort'][$hashKey])) {
            $hashValue = $this->createHashForValues($classOrAlias, $params);
            if (isset($this->sharedInstancesWithParams['hashLong'][$hashKey . '/' . $hashValue])) {
                return $this->sharedInstancesWithParams['hashLong'][$hashKey . '/' . $hashValue];
            }
        }

        return false;
    }

    /**
     * Check for an alias
     *
     * @param  string $alias
     * @return bool
     */
    public function hasAlias($alias)
    {
        return (isset($this->aliases[$alias]));
    }

    /**
     * Get aliases
     *
     * @return array
     */
    public function getAliases()
    {
        return $this->aliases;
    }

    /**
     * getClassFromAlias()
     *
     * @param string
     * @return string|bool
     * @throws Exception\RuntimeException
     */
    public function getClassFromAlias($alias)
    {
        if (!isset($this->aliases[$alias])) {
            return false;
        }
        $r = 0;
        while (isset($this->aliases[$alias])) {
            $alias = $this->aliases[$alias];
            $r++;
            if ($r > 100) {
                throw new Exception\RuntimeException(
                    sprintf('Possible infinite recursion in DI alias! Max recursion of 100 levels reached at alias "%s".', $alias)
                );
            }
        }

        return $alias;
    }

    /**
     * @param  string                     $alias
     * @return string|bool
     * @throws Exception\RuntimeException
     */
    protected function getBaseAlias($alias)
    {
        if (!$this->hasAlias($alias)) {
            return false;
        }
        $lastAlias = false;
        $r = 0;
        while (isset($this->aliases[$alias])) {
            $lastAlias = $alias;
            $alias = $this->aliases[$alias];
            $r++;
            if ($r > 100) {
                throw new Exception\RuntimeException(
                    sprintf('Possible infinite recursion in DI alias! Max recursion of 100 levels reached at alias "%s".', $alias)
                );
            }
        }

        return $lastAlias;
    }

    /**
     * Add alias
     *
     * @throws Exception\InvalidArgumentException
     * @param  string                             $alias
     * @param  string                             $class
     * @param  array                              $parameters
     * @return void
     */
    public function addAlias($alias, $class, array $parameters = [])
    {
        if (!preg_match('#^[a-zA-Z0-9-_]+$#', $alias)) {
            throw new Exception\InvalidArgumentException(
                'Aliases must be alphanumeric and can contain dashes and underscores only.'
            );
        }
        $this->aliases[$alias] = $class;
        if ($parameters) {
            $this->setParameters($alias, $parameters);
        }
    }

    /**
     * Check for configuration
     *
     * @param  string $aliasOrClass
     * @return bool
     */
    public function hasConfig($aliasOrClass)
    {
        $key = ($this->hasAlias($aliasOrClass)) ? 'alias:' . $this->getBaseAlias($aliasOrClass) : $aliasOrClass;
        if (!isset($this->configurations[$key])) {
            return false;
        }
        if ($this->configurations[$key] === $this->configurationTemplate) {
            return false;
        }

        return true;
    }

    /**
     * Sets configuration for a single alias/class
     *
     * @param string $aliasOrClass
     * @param array  $configuration
     * @param bool   $append
     */
    public function setConfig($aliasOrClass, array $configuration, $append = false)
    {
        $key = ($this->hasAlias($aliasOrClass)) ? 'alias:' . $this->getBaseAlias($aliasOrClass) : $aliasOrClass;
        if (!isset($this->configurations[$key]) || !$append) {
            $this->configurations[$key] = $this->configurationTemplate;
        }
        // Ignore anything but 'parameters' and 'injections'
        $configuration = [
            'parameters' => isset($configuration['parameters']) ? $configuration['parameters'] : [],
            'injections' => isset($configuration['injections']) ? $configuration['injections'] : [],
            'shared'     => isset($configuration['shared'])     ? $configuration['shared']     : true
        ];
        $this->configurations[$key] = array_replace_recursive($this->configurations[$key], $configuration);
    }

    /**
     * Get classes
     *
     * @return array
     */
    public function getClasses()
    {
        $classes = [];
        foreach ($this->configurations as $name => $data) {
            if (strpos($name, 'alias') === 0) {
                continue;
            }

            $classes[] = $name;
        }

        return $classes;
    }

    /**
     * @param  string $aliasOrClass
     * @return array
     */
    public function getConfig($aliasOrClass)
    {
        $key = ($this->hasAlias($aliasOrClass)) ? 'alias:' . $this->getBaseAlias($aliasOrClass) : $aliasOrClass;
        if (isset($this->configurations[$key])) {
            return $this->configurations[$key];
        }

        return $this->configurationTemplate;
    }

    /**
     * setParameters() is a convenience method for:
     *    setConfig($type, array('parameters' => array(...)), true);
     *
     * @param  string $aliasOrClass Alias or Class
     * @param  array  $parameters   Multi-dim array of parameters and their values
     * @return void
     */
    public function setParameters($aliasOrClass, array $parameters)
    {
        $this->setConfig($aliasOrClass, ['parameters' => $parameters], true);
    }

    /**
     * setInjections() is a convenience method for:
     *    setConfig($type, array('injections' => array(...)), true);
     *
     * @param  string $aliasOrClass Alias or Class
     * @param  array  $injections   Multi-dim array of methods and their parameters
     * @return void
     */
    public function setInjections($aliasOrClass, array $injections)
    {
        $this->setConfig($aliasOrClass, ['injections' => $injections], true);
    }

    /**
     * Set shared
     *
     * @param  string $aliasOrClass
     * @param  bool   $isShared
     * @return void
     */
    public function setShared($aliasOrClass, $isShared)
    {
        $this->setConfig($aliasOrClass, ['shared' => (bool) $isShared], true);
    }

    /**
     * Check for type preferences
     *
     * @param  string $interfaceOrAbstract
     * @return bool
     */
    public function hasTypePreferences($interfaceOrAbstract)
    {
        $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract;

        return (isset($this->typePreferences[$key]) && $this->typePreferences[$key]);
    }

    /**
     * Set type preference
     *
     * @param  string          $interfaceOrAbstract
     * @param  array           $preferredImplementations
     * @return InstanceManager
     */
    public function setTypePreference($interfaceOrAbstract, array $preferredImplementations)
    {
        $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract;
        foreach ($preferredImplementations as $preferredImplementation) {
            $this->addTypePreference($key, $preferredImplementation);
        }

        return $this;
    }

    /**
     * Get type preferences
     *
     * @param  string $interfaceOrAbstract
     * @return array
     */
    public function getTypePreferences($interfaceOrAbstract)
    {
        $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract;
        if (isset($this->typePreferences[$key])) {
            return $this->typePreferences[$key];
        }

        return [];
    }

    /**
     * Unset type preferences
     *
     * @param  string $interfaceOrAbstract
     * @return void
     */
    public function unsetTypePreferences($interfaceOrAbstract)
    {
        $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract;
        unset($this->typePreferences[$key]);
    }

    /**
     * Adds a type preference. A type preference is a redirection to a preferred alias or type when an abstract type
     * $interfaceOrAbstract is requested
     *
     * @param  string $interfaceOrAbstract
     * @param  string $preferredImplementation
     * @return self
     */
    public function addTypePreference($interfaceOrAbstract, $preferredImplementation)
    {
        $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract;
        if (!isset($this->typePreferences[$key])) {
            $this->typePreferences[$key] = [];
        }
        $this->typePreferences[$key][] = $preferredImplementation;

        return $this;
    }

    /**
     * Removes a previously set type preference
     *
     * @param  string    $interfaceOrAbstract
     * @param  string    $preferredType
     * @return bool|self
     */
    public function removeTypePreference($interfaceOrAbstract, $preferredType)
    {
        $key = ($this->hasAlias($interfaceOrAbstract)) ? 'alias:' . $interfaceOrAbstract : $interfaceOrAbstract;
        if (!isset($this->typePreferences[$key]) || !in_array($preferredType, $this->typePreferences[$key])) {
            return false;
        }
        unset($this->typePreferences[$key][array_search($key, $this->typePreferences)]);

        return $this;
    }

    /**
     * @param  string   $classOrAlias
     * @param  string[] $paramKeys
     * @return string
     */
    protected function createHashForKeys($classOrAlias, $paramKeys)
    {
        return $classOrAlias . ':' . implode('|', $paramKeys);
    }

    /**
     * @param  string $classOrAlias
     * @param  array  $paramValues
     * @return string
     */
    protected function createHashForValues($classOrAlias, $paramValues)
    {
        $hashValue = '';
        foreach ($paramValues as $param) {
            switch (gettype($param)) {
                case 'object':
                    $hashValue .= spl_object_hash($param) . '|';
                    break;
                case 'integer':
                case 'string':
                case 'boolean':
                case 'NULL':
                case 'double':
                    $hashValue .= $param . '|';
                    break;
                case 'array':
                    $hashValue .= $this->createHashForValues($classOrAlias, $param) . '|';
                    break;
                case 'resource':
                    $hashValue .= 'resource|';
                    break;
            }
        }

        return $hashValue;
    }
}