/** * Create an object using the factory defined in the given binding. * * @param Binding $binding * @param InjectionPointInterface $point * @return object */ protected function createObjectUsingFactory(Binding $binding, InjectionPointInterface $point = NULL) { $callback = $binding->getTarget(); if (is_array($callback)) { $callback = [$this->get($callback[0]), $callback[1]]; $ref = new \ReflectionMethod(get_class($callback[0]), $callback[1]); } else { $ref = new \ReflectionFunction($callback); } $resolvers = (array) $binding->getResolvers(); // Special case: inject config of the type to be created into the factory: foreach ($ref->getParameters() as $param) { if ($this->getParamType($param) === Configuration::class) { $resolvers[$param->name] = $this->config->getConfig(str_replace('\\', '.', $binding->getTypeName())); } } $args = $this->populateArguments($ref, 0, $resolvers, $point); switch (count($args)) { case 0: $object = $callback(); break; case 1: $object = $callback($args[0]); break; case 2: $object = $callback($args[0], $args[1]); break; case 3: $object = $callback($args[0], $args[1], $args[2]); break; case 4: $object = $callback($args[0], $args[1], $args[2], $args[3]); break; default: $object = call_user_func_array($callback, $args); } if ($object instanceof ScopedProxyInterface) { return $object; } $object = $this->initialize($object); foreach ($binding->getMarkers(SetterInjection::class) as $setter) { $this->performSetterInjection($object, $setter); } $initializers = $binding->getInitializers(); if (!empty($initializers)) { $object = $this->invokeBindingInitializers($binding->getTypeName(), $object, $initializers); } return $object; }
/** * Compiles an inline factory binding by creating a replacement method in the DI container. * * @param Binding $binding * @return string */ protected function compileInlineFactoryBinding(Binding $binding) { $code = ''; $num = count($this->methods); $ref = new \ReflectionFunction($binding->getTarget()); $sig = $this->generateReplacementMethodSignature($ref, $num); $body = $this->extractClosureCode($ref); $this->methods[] = "\t\t" . $sig . " {\n" . $body . "\n\t\t}"; $resolvers = (array) $binding->getResolvers(); foreach ($ref->getParameters() as $param) { if ($this->getParamType($param) === Configuration::class) { $con = "\$this->config->getConfig(" . var_export(str_replace('\\', '.', $binding->getTypeName()), true) . ')'; $resolvers[$param->name] = new CompiledCodeFragment($con); } } foreach ($ref->getParameters() as $param) { if (!$param->isOptional() && InjectionPointInterface::class === $this->getParamType($param)) { $code .= "\t\tif(\$point === NULL) {\n"; $code .= "\t\t\tthrow new ContextLookupException("; $code .= var_export(sprintf('Factory for %s requires access to an injection point', $binding->getTypeName()), true); $code .= ");\n"; $code .= "\t\t}\n"; } } $call = $this->generateCallCode($binding->getTypeName(), $ref, $num, [], $resolvers); $setterInjection = $binding->isMarked(SetterInjection::class); $initializers = (array) $binding->getInitializers(); if (empty($initializers) && !$setterInjection) { $code .= "\t\treturn \$this->initialize(" . $call . ");\n"; } else { $code .= "\t\t\$obj = \$this->initialize(" . $call . ");\n"; if ($setterInjection) { $code .= "\t\t" . $this->compileSetterInjector($binding, false) . "\n"; } foreach ($initializers as $initializer) { $num = count($this->methods); $ref = new \ReflectionFunction($initializer); $sig = $this->generateReplacementMethodSignature($ref, $num); $body = $this->extractClosureCode($ref); $this->methods[] = "\t\t" . $sig . " {\n" . $body . "\n\t\t}"; $code .= "\t\t\$obj = " . $this->generateCallCode($binding->getTypeName(), $ref, $num, ['$obj']) . " ?: \$obj;\n"; } $code .= "\t\treturn \$obj;\n"; } return $code; }