Title: ClassDiscovery
Published: May 20, 2026

---

# class ClassDiscovery {}

## In this article

 * [Methods](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/?output_format=md#methods)
 * [Source](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/?output_format=md#source)

[ Back to top](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/?output_format=md#wp--skip-link--target)

Registry that based find results on class existence.

## 󠀁[Methods](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/?output_format=md#methods)󠁿

| Name | Description | 
| [ClassDiscovery::appendStrategy](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/appendstrategy/) | Append a strategy at the end of the strategy queue. | 
| [ClassDiscovery::clearCache](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/clearcache/) | – | 
| [ClassDiscovery::evaluateCondition](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/evaluatecondition/) | Evaluates conditions to boolean. | 
| [ClassDiscovery::findOneByType](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/findonebytype/) | Finds a class. | 
| [ClassDiscovery::getFromCache](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/getfromcache/) | Get a value from cache. | 
| [ClassDiscovery::getStrategies](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/getstrategies/) | Returns the currently configured discovery strategies as fully qualified class names. | 
| [ClassDiscovery::instantiateClass](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/instantiateclass/) | Get an instance of the $class. | 
| [ClassDiscovery::prependStrategy](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/prependstrategy/) | Prepend a strategy at the beginning of the strategy queue. | 
| [ClassDiscovery::safeClassExists](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/safeclassexists/) | We need a “safe” version of PHP’s “class_exists” because Magento has a bug (or they call it a “feature”). Magento is throwing an exception if you do class_exists() on a class that ends with “Factory” and if that file does not exits. | 
| [ClassDiscovery::setStrategies](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/setstrategies/) | Set new strategies and clear the cache. | 
| [ClassDiscovery::storeInCache](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/storeincache/) | Store a value in cache. |

## 󠀁[Source](https://developer.wordpress.org/reference/classes/wordpress-aiclientdependencies-http-discovery-classdiscovery/?output_format=md#source)󠁿

    ```php
    abstract class ClassDiscovery
    {
        /**
         * A list of strategies to find classes.
         *
         * @var DiscoveryStrategy[]
         */
        private static $strategies = [Strategy\GeneratedDiscoveryStrategy::class, Strategy\CommonClassesStrategy::class, Strategy\CommonPsr17ClassesStrategy::class, Strategy\PuliBetaStrategy::class];
        private static $deprecatedStrategies = [Strategy\PuliBetaStrategy::class => \true];
        /**
         * Discovery cache to make the second time we use discovery faster.
         *
         * @var array
         */
        private static $cache = [];
        /**
         * Finds a class.
         *
         * @param string $type
         *
         * @return string|\Closure
         *
         * @throws DiscoveryFailedException
         */
        protected static function findOneByType($type)
        {
            // Look in the cache
            if (null !== $class = self::getFromCache($type)) {
                return $class;
            }
            static $skipStrategy;
            $skipStrategy ?? $skipStrategy = self::safeClassExists(Strategy\GeneratedDiscoveryStrategy::class) ? \false : Strategy\GeneratedDiscoveryStrategy::class;
            $exceptions = [];
            foreach (self::$strategies as $strategy) {
                if ($skipStrategy === $strategy) {
                    continue;
                }
                try {
                    $candidates = $strategy::getCandidates($type);
                } catch (StrategyUnavailableException $e) {
                    if (!isset(self::$deprecatedStrategies[$strategy])) {
                        $exceptions[] = $e;
                    }
                    continue;
                }
                foreach ($candidates as $candidate) {
                    if (isset($candidate['condition'])) {
                        if (!self::evaluateCondition($candidate['condition'])) {
                            continue;
                        }
                    }
                    // save the result for later use
                    self::storeInCache($type, $candidate);
                    return $candidate['class'];
                }
                $exceptions[] = new NoCandidateFoundException($strategy, $candidates);
            }
            throw DiscoveryFailedException::create($exceptions);
        }
        /**
         * Get a value from cache.
         *
         * @param string $type
         *
         * @return string|null
         */
        private static function getFromCache($type)
        {
            if (!isset(self::$cache[$type])) {
                return;
            }
            $candidate = self::$cache[$type];
            if (isset($candidate['condition'])) {
                if (!self::evaluateCondition($candidate['condition'])) {
                    return;
                }
            }
            return $candidate['class'];
        }
        /**
         * Store a value in cache.
         *
         * @param string $type
         * @param string $class
         */
        private static function storeInCache($type, $class)
        {
            self::$cache[$type] = $class;
        }
        /**
         * Set new strategies and clear the cache.
         *
         * @param string[] $strategies list of fully qualified class names that implement DiscoveryStrategy
         */
        public static function setStrategies(array $strategies)
        {
            self::$strategies = $strategies;
            self::clearCache();
        }
        /**
         * Returns the currently configured discovery strategies as fully qualified class names.
         *
         * @return string[]
         */
        public static function getStrategies(): iterable
        {
            return self::$strategies;
        }
        /**
         * Append a strategy at the end of the strategy queue.
         *
         * @param string $strategy Fully qualified class name of a DiscoveryStrategy
         */
        public static function appendStrategy($strategy)
        {
            self::$strategies[] = $strategy;
            self::clearCache();
        }
        /**
         * Prepend a strategy at the beginning of the strategy queue.
         *
         * @param string $strategy Fully qualified class name to a DiscoveryStrategy
         */
        public static function prependStrategy($strategy)
        {
            array_unshift(self::$strategies, $strategy);
            self::clearCache();
        }
        public static function clearCache()
        {
            self::$cache = [];
        }
        /**
         * Evaluates conditions to boolean.
         *
         * @return bool
         */
        protected static function evaluateCondition($condition)
        {
            if (is_string($condition)) {
                // Should be extended for functions, extensions???
                return self::safeClassExists($condition);
            }
            if (is_callable($condition)) {
                return (bool) $condition();
            }
            if (is_bool($condition)) {
                return $condition;
            }
            if (is_array($condition)) {
                foreach ($condition as $c) {
                    if (\false === static::evaluateCondition($c)) {
                        // Immediately stop execution if the condition is false
                        return \false;
                    }
                }
                return \true;
            }
            return \false;
        }
        /**
         * Get an instance of the $class.
         *
         * @param string|\Closure $class a FQCN of a class or a closure that instantiate the class
         *
         * @return object
         *
         * @throws ClassInstantiationFailedException
         */
        protected static function instantiateClass($class)
        {
            try {
                if (is_string($class)) {
                    return new $class();
                }
                if (is_callable($class)) {
                    return $class();
                }
            } catch (\Exception $e) {
                throw new ClassInstantiationFailedException('Unexpected exception when instantiating class.', 0, $e);
            }
            throw new ClassInstantiationFailedException('Could not instantiate class because parameter is neither a callable nor a string');
        }
        /**
         * We need a "safe" version of PHP's "class_exists" because Magento has a bug
         * (or they call it a "feature"). Magento is throwing an exception if you do class_exists()
         * on a class that ends with "Factory" and if that file does not exits.
         *
         * This function catches all potential exceptions and makes sure to always return a boolean.
         *
         * @param string $class
         *
         * @return bool
         */
        public static function safeClassExists($class)
        {
            try {
                return class_exists($class) || interface_exists($class);
            } catch (\Exception $e) {
                return \false;
            }
        }
    }
    ```

[View all references](https://developer.wordpress.org/reference/files/wp-includes/php-ai-client/third-party/http/discovery/classdiscovery.php/)
[View on Trac](https://core.trac.wordpress.org/browser/tags/7.0/src/wp-includes/php-ai-client/third-party/Http/Discovery/ClassDiscovery.php#L17)
[View on GitHub](https://github.com/WordPress/wordpress-develop/blob/7.0/src/wp-includes/php-ai-client/third-party/Http/Discovery/ClassDiscovery.php#L17-L219)

## User Contributed Notes

You must [log in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Fclasses%2Fwordpress-aiclientdependencies-http-discovery-classdiscovery%2F)
before being able to contribute a note or feedback.