/** * Generates list of arguments using autowiring. * @return array */ public static function autowireArguments(\ReflectionFunctionAbstract $method, array $arguments, $container) { $optCount = 0; $num = -1; $res = []; $methodName = ($method instanceof \ReflectionMethod ? $method->getDeclaringClass()->getName() . '::' : '') . $method->getName() . '()'; foreach ($method->getParameters() as $num => $parameter) { if (array_key_exists($num, $arguments)) { $res[$num] = $arguments[$num]; unset($arguments[$num]); $optCount = 0; } elseif (array_key_exists($parameter->getName(), $arguments)) { $res[$num] = $arguments[$parameter->getName()]; unset($arguments[$parameter->getName()]); $optCount = 0; } elseif ($class = PhpReflection::getPropertyType($parameter)) { // has object type hint $res[$num] = $container->getByType($class, FALSE); if ($res[$num] === NULL) { if ($parameter->allowsNull()) { $optCount++; } elseif (class_exists($class) || interface_exists($class)) { throw new ServiceCreationException("Service of type {$class} needed by {$methodName} not found. Did you register it in configuration file?"); } else { throw new ServiceCreationException("Class {$class} needed by {$methodName} not found. Check type hint and 'use' statements."); } } else { if ($container instanceof ContainerBuilder) { $res[$num] = '@' . $res[$num]; } $optCount = 0; } } elseif ($parameter->isOptional() || $parameter->isDefaultValueAvailable()) { // !optional + defaultAvailable = func($a = NULL, $b) since 5.4.7 // optional + !defaultAvailable = i.e. Exception::__construct, mysqli::mysqli, ... $res[$num] = $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : NULL; $optCount++; } else { throw new ServiceCreationException("Parameter \${$parameter->getName()} in {$methodName} has no type hint, so its value must be specified."); } } // extra parameters while (array_key_exists(++$num, $arguments)) { $res[$num] = $arguments[$num]; unset($arguments[$num]); $optCount = 0; } if ($arguments) { throw new ServiceCreationException("Unable to pass specified arguments to {$methodName}."); } return $optCount ? array_slice($res, 0, -$optCount) : $res; }
private function resolveImplement(ServiceDefinition $def, $name) { $interface = $def->getImplement(); if (!interface_exists($interface)) { throw new ServiceCreationException("Interface {$interface} used in service '{$name}' not found."); } self::checkCase($interface); $rc = new ReflectionClass($interface); $method = $rc->hasMethod('create') ? $rc->getMethod('create') : ($rc->hasMethod('get') ? $rc->getMethod('get') : NULL); if (count($rc->getMethods()) !== 1 || !$method || $method->isStatic()) { throw new ServiceCreationException("Interface {$interface} used in service '{$name}' must have just one non-static method create() or get()."); } $def->setImplementType($methodName = $rc->hasMethod('create') ? 'create' : 'get'); if (!$def->getClass() && !$def->getEntity()) { $returnType = PhpReflection::parseAnnotation($method, 'return'); if (!$returnType) { throw new ServiceCreationException("Method {$interface}::{$methodName}() used in service '{$name}' has no @return annotation."); } $returnType = PhpReflection::expandClassName(preg_replace('#[|\\s].*#', '', $returnType), $rc); if (!class_exists($returnType)) { throw new ServiceCreationException("Please check a @return annotation of the {$interface}::{$methodName}() method used in service '{$name}'. Class '{$returnType}' cannot be found."); } $def->setClass($returnType); } if ($methodName === 'get') { if ($method->getParameters()) { throw new ServiceCreationException("Method {$interface}::get() used in service '{$name}' must have no arguments."); } if (!$def->getEntity()) { $def->setFactory('@\\' . ltrim($def->getClass(), '\\')); } elseif (!$this->getServiceName($def->getFactory()->getEntity())) { throw new ServiceCreationException("Invalid factory in service '{$name}' definition."); } } if (!$def->parameters) { $ctorParams = array(); if (!$def->getEntity()) { $def->setFactory($def->getClass(), $def->getFactory() ? $def->getFactory()->arguments : array()); } if (($class = $this->resolveEntityClass($def->getFactory(), array($name => 1))) && ($rc = new ReflectionClass($class)) && ($ctor = $rc->getConstructor())) { foreach ($ctor->getParameters() as $param) { $ctorParams[$param->getName()] = $param; } } foreach ($method->getParameters() as $param) { $hint = $param->isArray() ? 'array' : PhpReflection::getPropertyType($param); if (isset($ctorParams[$param->getName()])) { $arg = $ctorParams[$param->getName()]; if ($hint !== ($arg->isArray() ? 'array' : PhpReflection::getPropertyType($arg))) { throw new ServiceCreationException("Type hint for \${$param->getName()} in {$interface}::{$methodName}() doesn't match type hint in {$class} constructor."); } $def->getFactory()->arguments[$arg->getPosition()] = ContainerBuilder::literal('$' . $arg->getName()); } $paramDef = $hint . ' ' . $param->getName(); if ($param->isOptional()) { $def->parameters[$paramDef] = $param->getDefaultValue(); } else { $def->parameters[] = $paramDef; } } } }