<commit_before><?php

namespace core\container;

class Container
{
    private $classes;
    private $objects;
    private $singletons;
    private $injections;
    
    public function __construct()
    {
        $this->initialize();
        $this->injections = simplexml_load_file(INJECT_FILE);
    }
    
    private function initialize()
    {
        $it = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(APPLICATION_ROOT_PATH));
        foreach ($it as $path)
        {
            if (!$it->isDot())
            {
                $namespace = $it->getSubPath();
                $classname = $path->getBasename('.php');
                $class = $namespace . '\\' . $classname;
                $this->classes[$classname] = $class;
                $this->objects[$classname] = function () use($class)
                {
                    return new $class();
                };
            }
        }
    }
    
    public function create($key)
    {
        if (isset($this->objects[$key]))
        {
            $object = $this->objects[$key]();
            return $this->inject($key, $object);
        }
        throw new CreateException("Cannot create instance of a class by the given key: $key");
    }
    
    public function singleton($key)
    {
        if (isset($this->singletons[$key]))
        {
            return $this->singletons[$key];
        }
        return $this->singletons[$key] = $this->create($key);
    }
    
    public function inject($key, $object)
    {
        $reflection = new \ReflectionObject($object);
        $properties = $reflection->getProperties();
        foreach ($properties as $property)
        {
            $fields = $this->injections->xpath('//class[@name = "' . $key . '"]/field[@name = "'. $property->name . '"]');
            foreach ($fields as $field)
            {
                $method = (string) $field['singleton'] == 'true' ? 'singleton' : 'create';
                $dependency = $this->{$method}((string) $field['type']);
                
                if ($reflection->hasMethod($setter = 'set'.$property->name))
                {
                    $object->$setter($dependency);
                }
                else
                {
                    if (isset($field['supertype']))
                    {
                        $super = $this->classes[(string) $field['supertype']];
                        if (!($dependency instanceof $super))
                        {
                            throw new IncorrectInjectionSupertypeException("{$field['type']} is not an instance of $super");
                        }
                    }
                    $property->setAccessible(true);
                    $property->setValue($object, $dependency);
                }
            }
        }
        return $object;
    }
    
    /**
     * Explicitly binds class to a key in the Container
     * for later creation as a normal instance or a singleton 
     * @param unknown $key a reference to the registered container class
     * @param unknown $closure code to be executed on invocation
     */
    public function bind($key, $closure)
    {
        $this->objects[$key] = $closure;
    }
}

?><commit_msg>#3 PHPDoc for Container::inject method.<commit_after><?php

namespace core\container;

class Container
{
    private $classes;
    private $objects;
    private $singletons;
    private $injections;
    
    public function __construct()
    {
        $this->initialize();
        $this->injections = simplexml_load_file(INJECT_FILE);
    }
    
    private function initialize()
    {
        $it = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(APPLICATION_ROOT_PATH));
        foreach ($it as $path)
        {
            if (!$it->isDot())
            {
                $namespace = $it->getSubPath();
                $classname = $path->getBasename('.php');
                $class = $namespace . '\\' . $classname;
                $this->classes[$classname] = $class;
                $this->objects[$classname] = function () use($class)
                {
                    return new $class();
                };
            }
        }
    }
    
    public function create($key)
    {
        if (isset($this->objects[$key]))
        {
            $object = $this->objects[$key]();
            return $this->inject($key, $object);
        }
        throw new CreateException("Cannot create instance of a class by the given key: $key");
    }
    
    public function singleton($key)
    {
        if (isset($this->singletons[$key]))
        {
            return $this->singletons[$key];
        }
        return $this->singletons[$key] = $this->create($key);
    }
    
    /**
     * Injects shared or new instances of dependency classes
     * to the given object based on reflection and injection
     * configuration.
     * 
     * @param string $key a reference to a registered container class
     * @param object $object target of injections
     * @throws IncorrectInjectionSupertypeException
     * @return object an instance with fields injected
     */
    public function inject($key, $object)
    {
        $reflection = new \ReflectionObject($object);
        $properties = $reflection->getProperties();
        foreach ($properties as $property)
        {
            $fields = $this->injections->xpath('//class[@name = "' . $key . '"]/field[@name = "'. $property->name . '"]');
            foreach ($fields as $field)
            {
                $method = (string) $field['singleton'] == 'true' ? 'singleton' : 'create';
                $dependency = $this->{$method}((string) $field['type']);
                
                if ($reflection->hasMethod($setter = 'set'.$property->name))
                {
                    $object->$setter($dependency);
                }
                else
                {
                    if (isset($field['supertype']))
                    {
                        $super = $this->classes[(string) $field['supertype']];
                        if (!($dependency instanceof $super))
                        {
                            throw new IncorrectInjectionSupertypeException("{$field['type']} is not an instance of $super");
                        }
                    }
                    $property->setAccessible(true);
                    $property->setValue($object, $dependency);
                }
            }
        }
        return $object;
    }
    
    /**
     * Explicitly binds class to a key in the Container
     * for later creation as a normal instance or a singleton.
     * 
     * @param string $key a reference to a registered container class
     * @param object $closure code to be executed on invocation
     */
    public function bind($key, $closure)
    {
        $this->objects[$key] = $closure;
    }
}

?>
{'fraction_non_alphanumeric': 0.13129102844638948, 'fraction_numerical': 0.00014587892049598833, 'mean_word_length': 1.5940219447597428, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, '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': '3724258', 'n_tokens_mistral': 1807, 'n_tokens_neox': 1734, 'n_words': 413}