File "ObjectCreationCompiler.php"
Full Path: /home/rattkxnv/byattorney.com/wp-content/plugins/elementor/vendor_prefixed/dependency-injection/php-di/php-di/src/Compiler/ObjectCreationCompiler.php
File size: 6.63 KB
MIME-type: text/x-php
Charset: utf-8
<?php
declare (strict_types=1);
namespace ElementorDeps\DI\Compiler;
use ElementorDeps\DI\Definition\Exception\InvalidDefinition;
use ElementorDeps\DI\Definition\ObjectDefinition;
use ElementorDeps\DI\Definition\ObjectDefinition\MethodInjection;
use ReflectionClass;
use ReflectionMethod;
use ReflectionParameter;
use ReflectionProperty;
/**
* Compiles an object definition into native PHP code that, when executed, creates the object.
*
* @author Matthieu Napoli <matthieu@mnapoli.fr>
*/
class ObjectCreationCompiler
{
/**
* @var Compiler
*/
private $compiler;
public function __construct(Compiler $compiler)
{
$this->compiler = $compiler;
}
public function compile(ObjectDefinition $definition) : string
{
$this->assertClassIsNotAnonymous($definition);
$this->assertClassIsInstantiable($definition);
// Lazy?
if ($definition->isLazy()) {
return $this->compileLazyDefinition($definition);
}
try {
$classReflection = new ReflectionClass($definition->getClassName());
$constructorArguments = $this->resolveParameters($definition->getConstructorInjection(), $classReflection->getConstructor());
$dumpedConstructorArguments = \array_map(function ($value) {
return $this->compiler->compileValue($value);
}, $constructorArguments);
$code = [];
$code[] = \sprintf('$object = new %s(%s);', $definition->getClassName(), \implode(', ', $dumpedConstructorArguments));
// Property injections
foreach ($definition->getPropertyInjections() as $propertyInjection) {
$value = $propertyInjection->getValue();
$value = $this->compiler->compileValue($value);
$className = $propertyInjection->getClassName() ?: $definition->getClassName();
$property = new ReflectionProperty($className, $propertyInjection->getPropertyName());
if ($property->isPublic()) {
$code[] = \sprintf('$object->%s = %s;', $propertyInjection->getPropertyName(), $value);
} else {
// Private/protected property
$code[] = \sprintf('\\DI\\Definition\\Resolver\\ObjectCreator::setPrivatePropertyValue(%s, $object, \'%s\', %s);', \var_export($propertyInjection->getClassName(), \true), $propertyInjection->getPropertyName(), $value);
}
}
// Method injections
foreach ($definition->getMethodInjections() as $methodInjection) {
$methodReflection = new \ReflectionMethod($definition->getClassName(), $methodInjection->getMethodName());
$parameters = $this->resolveParameters($methodInjection, $methodReflection);
$dumpedParameters = \array_map(function ($value) {
return $this->compiler->compileValue($value);
}, $parameters);
$code[] = \sprintf('$object->%s(%s);', $methodInjection->getMethodName(), \implode(', ', $dumpedParameters));
}
} catch (InvalidDefinition $e) {
throw InvalidDefinition::create($definition, \sprintf('Entry "%s" cannot be compiled: %s', $definition->getName(), $e->getMessage()));
}
return \implode("\n ", $code);
}
public function resolveParameters(MethodInjection $definition = null, ReflectionMethod $method = null) : array
{
$args = [];
if (!$method) {
return $args;
}
$definitionParameters = $definition ? $definition->getParameters() : [];
foreach ($method->getParameters() as $index => $parameter) {
if (\array_key_exists($index, $definitionParameters)) {
// Look in the definition
$value =& $definitionParameters[$index];
} elseif ($parameter->isOptional()) {
// If the parameter is optional and wasn't specified, we take its default value
$args[] = $this->getParameterDefaultValue($parameter, $method);
continue;
} else {
throw new InvalidDefinition(\sprintf('Parameter $%s of %s has no value defined or guessable', $parameter->getName(), $this->getFunctionName($method)));
}
$args[] =& $value;
}
return $args;
}
private function compileLazyDefinition(ObjectDefinition $definition) : string
{
$subDefinition = clone $definition;
$subDefinition->setLazy(\false);
$subDefinition = $this->compiler->compileValue($subDefinition);
$this->compiler->getProxyFactory()->generateProxyClass($definition->getClassName());
return <<<PHP
\$object = \$this->proxyFactory->createProxy(
'{$definition->getClassName()}',
function (&\$wrappedObject, \$proxy, \$method, \$params, &\$initializer) {
\$wrappedObject = {$subDefinition};
\$initializer = null; // turning off further lazy initialization
return true;
}
);
PHP;
}
/**
* Returns the default value of a function parameter.
*
* @throws InvalidDefinition Can't get default values from PHP internal classes and functions
* @return mixed
*/
private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function)
{
try {
return $parameter->getDefaultValue();
} catch (\ReflectionException $e) {
throw new InvalidDefinition(\sprintf('The parameter "%s" of %s has no type defined or guessable. It has a default value, ' . 'but the default value can\'t be read through Reflection because it is a PHP internal class.', $parameter->getName(), $this->getFunctionName($function)));
}
}
private function getFunctionName(ReflectionMethod $method) : string
{
return $method->getName() . '()';
}
private function assertClassIsNotAnonymous(ObjectDefinition $definition)
{
if (\strpos($definition->getClassName(), '@') !== \false) {
throw InvalidDefinition::create($definition, \sprintf('Entry "%s" cannot be compiled: anonymous classes cannot be compiled', $definition->getName()));
}
}
private function assertClassIsInstantiable(ObjectDefinition $definition)
{
if ($definition->isInstantiable()) {
return;
}
$message = !$definition->classExists() ? 'Entry "%s" cannot be compiled: the class doesn\'t exist' : 'Entry "%s" cannot be compiled: the class is not instantiable';
throw InvalidDefinition::create($definition, \sprintf($message, $definition->getName()));
}
}