<commit_before><?php

namespace DI\Definition\Resolver;

use DI\Definition\Definition;
use DI\Definition\Exception\DefinitionException;
use DI\Definition\Helper\DefinitionHelper;
use DI\Definition\ObjectDefinition;
use DI\Definition\ObjectDefinition\PropertyInjection;
use DI\DependencyException;
use DI\Proxy\ProxyFactory;
use Exception;
use Interop\Container\Exception\NotFoundException;
use ProxyManager\Proxy\LazyLoadingInterface;
use ReflectionClass;
use ReflectionProperty;

/**
 * Create objects based on an object definition.
 *
 * @since 4.0
 * @author <NAME> <<EMAIL>>
 */
class ObjectCreator implements DefinitionResolver
{
    /**
     * @var ProxyFactory
     */
    private $proxyFactory;

    /**
     * @var ParameterResolver
     */
    private $parameterResolver;

    /**
     * @var DefinitionResolver
     */
    private $definitionResolver;

    /**
     * @param DefinitionResolver $definitionResolver Used to resolve nested definitions.
     * @param ProxyFactory       $proxyFactory       Used to create proxies for lazy injections.
     */
    public function __construct(
        DefinitionResolver $definitionResolver,
        ProxyFactory $proxyFactory
    ) {
        $this->definitionResolver = $definitionResolver;
        $this->proxyFactory = $proxyFactory;
        $this->parameterResolver = new ParameterResolver($definitionResolver);
    }

    /**
     * Resolve a class definition to a value.
     *
     * This will create a new instance of the class using the injections points defined.
     *
     * @param ObjectDefinition $definition
     *
     * {@inheritdoc}
     */
    public function resolve(Definition $definition, array $parameters = [])
    {
        // Lazy?
        if ($definition->isLazy()) {
            return $this->createProxy($definition, $parameters);
        }

        return $this->createInstance($definition, $parameters);
    }

    /**
     * The definition is not resolvable if the class is not instantiable (interface or abstract)
     * or if the class doesn't exist.
     *
     * @param ObjectDefinition $definition
     *
     * {@inheritdoc}
     */
    public function isResolvable(Definition $definition, array $parameters = [])
    {
        return $definition->isInstantiable();
    }

    /**
     * Returns a proxy instance.
     *
     * @param ObjectDefinition $definition
     * @param array           $parameters
     *
     * @return LazyLoadingInterface Proxy instance
     */
    private function createProxy(ObjectDefinition $definition, array $parameters)
    {
        /** @noinspection PhpUnusedParameterInspection */
        $proxy = $this->proxyFactory->createProxy(
            $definition->getClassName(),
            function (& $wrappedObject, $proxy, $method, $params, & $initializer) use ($definition, $parameters) {
                $wrappedObject = $this->createInstance($definition, $parameters);
                $initializer = null; // turning off further lazy initialization
                return true;
            }
        );

        return $proxy;
    }

    /**
     * Creates an instance of the class and injects dependencies..
     *
     * @param ObjectDefinition $definition
     * @param array            $parameters      Optional parameters to use to create the instance.
     *
     * @throws DefinitionException
     * @throws DependencyException
     * @return object
     */
    private function createInstance(ObjectDefinition $definition, array $parameters)
    {
        // Check that the class exists
        if (! $definition->classExists()) {
            throw DefinitionException::create($definition, sprintf(
                'Entry "%s" cannot be resolved: the class doesn\'t exist',
                $definition->getName()
            ));
        }

        $classname = $definition->getClassName();
        $classReflection = new ReflectionClass($classname);

        // Check that the class is instantiable
        if (! $definition->isInstantiable()) {
            throw DefinitionException::create($definition, sprintf(
                'Entry "%s" cannot be resolved: the class is not instantiable',
                $definition->getName()
            ));
        }

        $constructorInjection = $definition->getConstructorInjection();

        try {
            $args = $this->parameterResolver->resolveParameters(
                $constructorInjection,
                $classReflection->getConstructor(),
                $parameters
            );

            // Optimization trick
            switch (count($args)) {
                case 0:
                    $object = new $classname;<commit_msg>Optimization: reduce the number of `if` that runs<commit_after><?php

namespace DI\Definition\Resolver;

use DI\Definition\Definition;
use DI\Definition\Exception\DefinitionException;
use DI\Definition\Helper\DefinitionHelper;
use DI\Definition\ObjectDefinition;
use DI\Definition\ObjectDefinition\PropertyInjection;
use DI\DependencyException;
use DI\Proxy\ProxyFactory;
use Exception;
use Interop\Container\Exception\NotFoundException;
use ProxyManager\Proxy\LazyLoadingInterface;
use ReflectionClass;
use ReflectionProperty;

/**
 * Create objects based on an object definition.
 *
 * @since 4.0
 * @author <NAME> <<EMAIL>>
 */
class ObjectCreator implements DefinitionResolver
{
    /**
     * @var ProxyFactory
     */
    private $proxyFactory;

    /**
     * @var ParameterResolver
     */
    private $parameterResolver;

    /**
     * @var DefinitionResolver
     */
    private $definitionResolver;

    /**
     * @param DefinitionResolver $definitionResolver Used to resolve nested definitions.
     * @param ProxyFactory       $proxyFactory       Used to create proxies for lazy injections.
     */
    public function __construct(
        DefinitionResolver $definitionResolver,
        ProxyFactory $proxyFactory
    ) {
        $this->definitionResolver = $definitionResolver;
        $this->proxyFactory = $proxyFactory;
        $this->parameterResolver = new ParameterResolver($definitionResolver);
    }

    /**
     * Resolve a class definition to a value.
     *
     * This will create a new instance of the class using the injections points defined.
     *
     * @param ObjectDefinition $definition
     *
     * {@inheritdoc}
     */
    public function resolve(Definition $definition, array $parameters = [])
    {
        // Lazy?
        if ($definition->isLazy()) {
            return $this->createProxy($definition, $parameters);
        }

        return $this->createInstance($definition, $parameters);
    }

    /**
     * The definition is not resolvable if the class is not instantiable (interface or abstract)
     * or if the class doesn't exist.
     *
     * @param ObjectDefinition $definition
     *
     * {@inheritdoc}
     */
    public function isResolvable(Definition $definition, array $parameters = [])
    {
        return $definition->isInstantiable();
    }

    /**
     * Returns a proxy instance.
     *
     * @param ObjectDefinition $definition
     * @param array           $parameters
     *
     * @return LazyLoadingInterface Proxy instance
     */
    private function createProxy(ObjectDefinition $definition, array $parameters)
    {
        /** @noinspection PhpUnusedParameterInspection */
        $proxy = $this->proxyFactory->createProxy(
            $definition->getClassName(),
            function (& $wrappedObject, $proxy, $method, $params, & $initializer) use ($definition, $parameters) {
                $wrappedObject = $this->createInstance($definition, $parameters);
                $initializer = null; // turning off further lazy initialization
                return true;
            }
        );

        return $proxy;
    }

    /**
     * Creates an instance of the class and injects dependencies..
     *
     * @param ObjectDefinition $definition
     * @param array            $parameters      Optional parameters to use to create the instance.
     *
     * @throws DefinitionException
     * @throws DependencyException
     * @return object
     */
    private function createInstance(ObjectDefinition $definition, array $parameters)
    {
        // Check that the class is instantiable
        if (! $definition->isInstantiable()) {
            // Check that the class exists
            if (! $definition->classExists()) {
                throw DefinitionException::create($definition, sprintf(
                    'Entry "%s" cannot be resolved: the class doesn\'t exist',
                    $definition->getName()
                ));
            }

            throw DefinitionException::create($definition, sprintf(
                'Entry "%s" cannot be resolved: the class is not instantiable',
                $definition->getName()
            ));
        }

        $classname = $definition->getClassName();
        $classReflection = new ReflectionClass($classname);

        $constructorInjection = $definition->getConstructorInjection();

        try {
            $args = $this->parameterResolver->resolveParameters(
                $constructorInjection,
                $classReflection->getConstructor(),
                $parameters
            );

            // Optimization trick
            switch (count($args)) {
                case 0:
                    $object = new $classname;
{'fraction_non_alphanumeric': 0.09884343542514457, 'fraction_numerical': 0.000642535874919683, 'mean_word_length': 2.323487544483986, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5890726', 'n_tokens_mistral': 2278, 'n_tokens_neox': 2210, 'n_words': 622}