PluginProbe
Elementor Website Builder – more than just a page builder / 3.26.4
Elementor Website Builder – more than just a page builder v3.26.4
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / vendor_prefixed / php-di / php-di / src / Compiler / ObjectCreationCompiler.php

ObjectCreationCompiler.php in Elementor Website Builder – more than just a page builder 3.26.4, at vendor_prefixed/php-di/php-di/src/Compiler/ObjectCreationCompiler.php

143 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare (strict_types=1);
4 namespace ElementorDeps\DI\Compiler;
5
6 use ElementorDeps\DI\Definition\Exception\InvalidDefinition;
7 use ElementorDeps\DI\Definition\ObjectDefinition;
8 use ElementorDeps\DI\Definition\ObjectDefinition\MethodInjection;
9 use ReflectionClass;
10 use ReflectionMethod;
11 use ReflectionParameter;
12 use ReflectionProperty;
13 /**
14 * Compiles an object definition into native PHP code that, when executed, creates the object.
15 *
16 * @author Matthieu Napoli <matthieu@mnapoli.fr>
17 */
18 class ObjectCreationCompiler
19 {
20 /**
21 * @var Compiler
22 */
23 private $compiler;
24 public function __construct(Compiler $compiler)
25 {
26 $this->compiler = $compiler;
27 }
28 public function compile(ObjectDefinition $definition) : string
29 {
30 $this->assertClassIsNotAnonymous($definition);
31 $this->assertClassIsInstantiable($definition);
32 // Lazy?
33 if ($definition->isLazy()) {
34 return $this->compileLazyDefinition($definition);
35 }
36 try {
37 $classReflection = new ReflectionClass($definition->getClassName());
38 $constructorArguments = $this->resolveParameters($definition->getConstructorInjection(), $classReflection->getConstructor());
39 $dumpedConstructorArguments = \array_map(function ($value) {
40 return $this->compiler->compileValue($value);
41 }, $constructorArguments);
42 $code = [];
43 $code[] = \sprintf('$object = new %s(%s);', $definition->getClassName(), \implode(', ', $dumpedConstructorArguments));
44 // Property injections
45 foreach ($definition->getPropertyInjections() as $propertyInjection) {
46 $value = $propertyInjection->getValue();
47 $value = $this->compiler->compileValue($value);
48 $className = $propertyInjection->getClassName() ?: $definition->getClassName();
49 $property = new ReflectionProperty($className, $propertyInjection->getPropertyName());
50 if ($property->isPublic()) {
51 $code[] = \sprintf('$object->%s = %s;', $propertyInjection->getPropertyName(), $value);
52 } else {
53 // Private/protected property
54 $code[] = \sprintf('\\DI\\Definition\\Resolver\\ObjectCreator::setPrivatePropertyValue(%s, $object, \'%s\', %s);', \var_export($propertyInjection->getClassName(), \true), $propertyInjection->getPropertyName(), $value);
55 }
56 }
57 // Method injections
58 foreach ($definition->getMethodInjections() as $methodInjection) {
59 $methodReflection = new \ReflectionMethod($definition->getClassName(), $methodInjection->getMethodName());
60 $parameters = $this->resolveParameters($methodInjection, $methodReflection);
61 $dumpedParameters = \array_map(function ($value) {
62 return $this->compiler->compileValue($value);
63 }, $parameters);
64 $code[] = \sprintf('$object->%s(%s);', $methodInjection->getMethodName(), \implode(', ', $dumpedParameters));
65 }
66 } catch (InvalidDefinition $e) {
67 throw InvalidDefinition::create($definition, \sprintf('Entry "%s" cannot be compiled: %s', $definition->getName(), $e->getMessage()));
68 }
69 return \implode("\n ", $code);
70 }
71 public function resolveParameters(MethodInjection $definition = null, ReflectionMethod $method = null) : array
72 {
73 $args = [];
74 if (!$method) {
75 return $args;
76 }
77 $definitionParameters = $definition ? $definition->getParameters() : [];
78 foreach ($method->getParameters() as $index => $parameter) {
79 if (\array_key_exists($index, $definitionParameters)) {
80 // Look in the definition
81 $value =& $definitionParameters[$index];
82 } elseif ($parameter->isOptional()) {
83 // If the parameter is optional and wasn't specified, we take its default value
84 $args[] = $this->getParameterDefaultValue($parameter, $method);
85 continue;
86 } else {
87 throw new InvalidDefinition(\sprintf('Parameter $%s of %s has no value defined or guessable', $parameter->getName(), $this->getFunctionName($method)));
88 }
89 $args[] =& $value;
90 }
91 return $args;
92 }
93 private function compileLazyDefinition(ObjectDefinition $definition) : string
94 {
95 $subDefinition = clone $definition;
96 $subDefinition->setLazy(\false);
97 $subDefinition = $this->compiler->compileValue($subDefinition);
98 $this->compiler->getProxyFactory()->generateProxyClass($definition->getClassName());
99 return <<<PHP
100 \$object = \$this->proxyFactory->createProxy(
101 '{$definition->getClassName()}',
102 function (&\$wrappedObject, \$proxy, \$method, \$params, &\$initializer) {
103 \$wrappedObject = {$subDefinition};
104 \$initializer = null; // turning off further lazy initialization
105 return true;
106 }
107 );
108 PHP;
109 }
110 /**
111 * Returns the default value of a function parameter.
112 *
113 * @throws InvalidDefinition Can't get default values from PHP internal classes and functions
114 * @return mixed
115 */
116 private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function)
117 {
118 try {
119 return $parameter->getDefaultValue();
120 } catch (\ReflectionException $e) {
121 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)));
122 }
123 }
124 private function getFunctionName(ReflectionMethod $method) : string
125 {
126 return $method->getName() . '()';
127 }
128 private function assertClassIsNotAnonymous(ObjectDefinition $definition)
129 {
130 if (\strpos($definition->getClassName(), '@') !== \false) {
131 throw InvalidDefinition::create($definition, \sprintf('Entry "%s" cannot be compiled: anonymous classes cannot be compiled', $definition->getName()));
132 }
133 }
134 private function assertClassIsInstantiable(ObjectDefinition $definition)
135 {
136 if ($definition->isInstantiable()) {
137 return;
138 }
139 $message = !$definition->classExists() ? 'Entry "%s" cannot be compiled: the class doesn\'t exist' : 'Entry "%s" cannot be compiled: the class is not instantiable';
140 throw InvalidDefinition::create($definition, \sprintf($message, $definition->getName()));
141 }
142 }
143