protected function createFromDefinition(array $definition)
    {
        if (!isset($definition['class'])) {
            throw new ContainerException(
                'Service could not be created from definition:'
                    . ' option "class" is not exists in definition array.'
            );
        }

        $className = $definition['class'];

        if (!class_exists($className)) {
            throw new ContainerException(sprintf(
                'Service could not be created from definition:'
                    . ' Class "%s" is not exists.',
                $className
            ));
        }

        $reflection = new \ReflectionClass($className);

        if (!$reflection->isInstantiable()) {
            throw new ContainerException(sprintf(
                'Service could not be created from definition:'
                    . ' Unable to create instance of class "%s".',
                $className
            ));
        }

        if (null !== ($constructor = $reflection->getConstructor())) {
            if (!isset($definition['args'])) {
                throw new ContainerException(
                    'Service could not be created from definition:'
                        . ' option "args" is not exists in definition array.'
                );
            }
            $params = $this->resolveArgs($constructor->getParameters(), $definition['args']);
            $service = $reflection->newInstanceArgs($params);
        } else {
            // we don't have a constructor
            $service = $reflection->newInstance();
        }

        if (!isset($definition['calls'])) {
            return $service;
        }

        $calls = isset($definition['calls']) ? $definition['calls'] : [];
        foreach ($calls as $method => $args) {
            if (!is_callable([$service, $method])) {
                throw new ContainerException(sprintf(
                    'Service could not be created from definition:'
                        . ' can not call method "%s" from class: "%s"',
                    $method,
                    $className
                ));
            }
            $method = new \ReflectionMethod($service, $method);
            $params = $method->getParameters();
            $arguments = is_array($args)
                    ? $this->resolveArgs($params, $args)
                    : [];
            $method->invokeArgs($service, $arguments);
        }

        return $service;
    }