| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | declare(strict_types=1); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | namespace Spiral\Core\Internal\Proxy; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |  * @internal | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |  */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  | final class ProxyClassRenderer | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |      * @param \ReflectionClass $type Interface reflection. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |      * @param string $className Class name to use in the generated code. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |      * @param bool $defineOverload Define __call() and __callStatic() methods. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |      * @param bool $attachContainer Attach container to the proxy. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |      * @return non-empty-string PHP code | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 | 6 |  |     public static function renderClass( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |         \ReflectionClass $type, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |         string $className, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |         bool $defineOverload = false, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |         bool $attachContainer = false, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |     ): string { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 | 6 |  |         $traits = $defineOverload ? [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 | 6 |  |             MagicCallTrait::class, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 | 6 |  |         ] : []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 | 6 |  |         if (\str_contains($className, '\\')) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 | 4 |  |             $classShortName = \substr($className, \strrpos($className, '\\') + 1); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 | 4 |  |             $classNamespaceStr = 'namespace ' . \substr($className, 0, \strrpos($className, '\\')) . ';'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |         } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 | 2 |  |             $classShortName = $className; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 | 2 |  |             $classNamespaceStr = ''; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 | 6 |  |         $interface = $type->getName(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 | 6 |  |         $classBody = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 | 6 |  |         foreach ($type->getMethods() as $method) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 | 6 |  |             if ($method->isConstructor()) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 | 2 |  |                 continue; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 | 4 |  |             $hasRefs = false; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 | 4 |  |             $return = $method->hasReturnType() && (string)$method->getReturnType() === 'void' ? '' : 'return '; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 | 4 |  |             $call = ($method->isStatic() ? '::' : '->') . $method->getName(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 | 4 |  |             $context = $method->isStatic() ? 'null' : '$this->__container_proxy_context'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 | 4 |  |             $containerStr = match (false) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 | 4 |  |                 $attachContainer => 'null', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |                 /** @see \Spiral\Core\Internal\Proxy\ProxyTrait::__container_proxy_container */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 | 4 |  |                 $method->isStatic() => '$this->__container_proxy_container', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 | 4 |  |                 default => \sprintf( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 | 4 |  |                     'throw new \Spiral\Core\Exception\Container\ContainerException(\'%s\')', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 | 4 |  |                     'Static method call is not allowed on a Proxy that was created without dynamic scope.', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 | 4 |  |                 ), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 | 4 |  |             }; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 | 4 |  |             $resolveStr = <<<PHP | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 | 4 |  |                 \\Spiral\\Core\\Internal\\Proxy\\Resolver::resolve( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 | 4 |  |                     '{$interface}', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 | 4 |  |                     {$context}, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 | 4 |  |                     {$containerStr}, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |                 ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 | 4 |  |                 PHP; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 | 4 |  |             $args = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 | 4 |  |             foreach ($method->getParameters() as $param) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 | 2 |  |                 $hasRefs = $hasRefs || $param->isPassedByReference(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 | 2 |  |                 $args[] = ($param->isVariadic() ? '...' : '') . '$' . $param->getName(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 | 4 |  |             if (!$hasRefs && !$method->isVariadic()) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 | 4 |  |                 $classBody[] = self::renderMethod( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 | 4 |  |                     $method, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 | 4 |  |                     <<<PHP | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 | 4 |  |                     {$return}{$resolveStr}{$call}(...\\func_get_args()); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 | 4 |  |                 PHP | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 | 4 |  |                 ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 | 4 |  |                 continue; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 | 1 |  |             $argsStr = \implode(', ', $args); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 | 1 |  |             if ($method->isVariadic()) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 | 1 |  |                 $classBody[] = self::renderMethod( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 | 1 |  |                     $method, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 | 1 |  |                     <<<PHP | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 | 1 |  |                     {$return}{$resolveStr}{$call}($argsStr); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 | 1 |  |                 PHP | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 | 1 |  |                 ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 | 1 |  |                 continue; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 | 1 |  |             $countParams = $method->getNumberOfParameters(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 | 1 |  |             $classBody[] = self::renderMethod( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 | 1 |  |                 $method, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 | 1 |  |                 <<<PHP | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 | 1 |  |                 {$return}{$resolveStr}{$call}($argsStr, ...\\array_slice(\\func_get_args(), {$countParams})); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 | 1 |  |             PHP | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 | 1 |  |             ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 | 6 |  |         $bodyStr = \implode("\n\n", $classBody); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 | 6 |  |         $traitsStr = $traits === [] ? '' : \implode( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 | 6 |  |             "\n    ", | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 | 6 |  |             \array_map(fn (string $trait): string => 'use \\' . \ltrim($trait, '\\') . ';', $traits) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 | 6 |  |         ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 | 6 |  |         return <<<PHP | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 | 6 |  |             $classNamespaceStr | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 | 6 |  |             final class $classShortName implements \\$interface { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |                 use \Spiral\Core\Internal\Proxy\ProxyTrait; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 | 6 |  |                 $traitsStr | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 | 6 |  |             $bodyStr | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 | 6 |  |             PHP; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 | 9 |  |     public static function renderMethod(\ReflectionMethod $m, string $body = ''): string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 | 9 |  |         return \sprintf( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 | 9 |  |             "public%s function %s%s(%s)%s {\n%s\n}", | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 | 9 |  |             $m->isStatic() ? ' static' : '', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 | 9 |  |             $m->returnsReference() ? '&' : '', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 | 9 |  |             $m->getName(), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 | 9 |  |             \implode(', ', \array_map([self::class, 'renderParameter'], $m->getParameters())), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 | 9 |  |             $m->hasReturnType() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 | 7 |  |                 ? ': ' . self::renderParameterTypes($m->getReturnType(), $m->getDeclaringClass()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 | 9 |  |                 : '', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 | 9 |  |             $body, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 | 9 |  |         ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 134 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 135 | 27 |  |     public static function renderParameter(\ReflectionParameter $param): string | 
            
                                                                        
                            
            
                                    
            
            
                | 136 |  |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 137 | 27 |  |         return \ltrim( | 
            
                                                                        
                            
            
                                    
            
            
                | 138 | 27 |  |             \sprintf( | 
            
                                                                        
                            
            
                                    
            
            
                | 139 | 27 |  |                 '%s %s%s%s%s', | 
            
                                                                        
                            
            
                                    
            
            
                | 140 | 27 |  |                 $param->hasType() ? self::renderParameterTypes($param->getType(), $param->getDeclaringClass()) : '', | 
            
                                                                        
                            
            
                                    
            
            
                | 141 | 27 |  |                 $param->isPassedByReference() ? '&' : '', | 
            
                                                                        
                            
            
                                    
            
            
                | 142 | 27 |  |                 $param->isVariadic() ? '...' : '', | 
            
                                                                        
                            
            
                                    
            
            
                | 143 | 27 |  |                 '$' . $param->getName(), | 
            
                                                                        
                            
            
                                    
            
            
                | 144 | 27 |  |                 $param->isOptional() && !$param->isVariadic() ? ' = ' . self::renderDefaultValue($param) : '', | 
            
                                                                        
                            
            
                                    
            
            
                | 145 | 27 |  |             ), | 
            
                                                                        
                            
            
                                    
            
            
                | 146 | 27 |  |             ' ' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 | 27 |  |         ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 | 28 |  |     public static function renderParameterTypes(\ReflectionType $types, \ReflectionClass $class): string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 | 28 |  |         if ($types instanceof \ReflectionNamedType) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 | 21 |  |             return ($types->allowsNull() && $types->getName() !== 'mixed' ? '?' : '') . ($types->isBuiltin() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 | 18 |  |                     ? $types->getName() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 | 21 |  |                     : self::normalizeClassType($types, $class)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 | 8 |  |         [$separator, $types] = match (true) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 | 8 |  |             $types instanceof \ReflectionUnionType => ['|', $types->getTypes()], | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 | 8 |  |             $types instanceof \ReflectionIntersectionType => ['&', $types->getTypes()], | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 | 8 |  |             default => throw new \Exception('Unknown type.'), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 | 8 |  |         }; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 | 8 |  |         $result = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 | 8 |  |         foreach ($types as $type) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 | 8 |  |             $result[] = $type->isBuiltin() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 | 7 |  |                 ? $type->getName() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 | 3 |  |                 : self::normalizeClassType($type, $class); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 | 8 |  |         return \implode($separator, $result); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 | 1 |  |     public static function renderDefaultValue(\ReflectionParameter $param): string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 | 1 |  |         if ($param->isDefaultValueConstant()) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |             $result = $param->getDefaultValueConstantName(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 178 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 179 |  |  |             return \explode('::', $result)[0] === 'self' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 180 |  |  |                 ? $result | 
            
                                                                                                            
                            
            
                                    
            
            
                | 181 |  |  |                 : '\\' . $result; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 182 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 183 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 184 | 1 |  |         $cut = self::cutDefaultValue($param); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 185 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 186 | 1 |  |         return \str_starts_with($cut, 'new ') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 187 |  |  |             ? $cut | 
            
                                                                                                            
                            
            
                                    
            
            
                | 188 | 1 |  |             : \var_export($param->getDefaultValue(), true); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 189 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 190 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 191 | 1 |  |     public static function normalizeClassType(\ReflectionNamedType $type, \ReflectionClass $class): string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 192 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 193 | 1 |  |         return '\\' . ($type->getName() === 'self' ? $class->getName() : $type->getName()); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 194 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 195 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 196 | 1 |  |     private static function cutDefaultValue(\ReflectionParameter $param): string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 197 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 198 | 1 |  |         $string = (string)$param; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 199 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 200 | 1 |  |         return \trim(\substr($string, \strpos($string, '=') + 1, -1)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 201 |  |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 202 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 203 |  |  |  |