vendor/friendsofphp/proxy-manager-lts/src/ProxyManager/Factory/AbstractBaseFactory.php line 107

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace ProxyManager\Factory;
  4. use OutOfBoundsException;
  5. use ProxyManager\Configuration;
  6. use ProxyManager\Generator\ClassGenerator;
  7. use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
  8. use ProxyManager\Signature\Exception\InvalidSignatureException;
  9. use ProxyManager\Signature\Exception\MissingSignatureException;
  10. use ProxyManager\Version;
  11. use ReflectionClass;
  12. use function array_key_exists;
  13. use function assert;
  14. use function class_exists;
  15. use function is_a;
  16. use function serialize;
  17. use function sha1;
  18. /**
  19. * Base factory common logic
  20. */
  21. abstract class AbstractBaseFactory
  22. {
  23. protected $configuration;
  24. /**
  25. * Cached checked class names
  26. *
  27. * @var array<string, string>
  28. * @psalm-var array<string, class-string>
  29. */
  30. private $checkedClasses = [];
  31. public function __construct(?Configuration $configuration = null)
  32. {
  33. $this->configuration = $configuration ?? new Configuration();
  34. }
  35. /**
  36. * Generate a proxy from a class name
  37. *
  38. * @param array<string, mixed> $proxyOptions
  39. * @psalm-param class-string<RealObjectType> $className
  40. *
  41. * @psalm-return class-string<RealObjectType>
  42. *
  43. * @throws InvalidSignatureException
  44. * @throws MissingSignatureException
  45. * @throws OutOfBoundsException
  46. *
  47. * @psalm-template RealObjectType of object
  48. */
  49. protected function generateProxy(string $className, array $proxyOptions = []): string
  50. {
  51. $cacheKey = $proxyOptions ? sha1(serialize([$className, $proxyOptions])) : $className;
  52. if (array_key_exists($cacheKey, $this->checkedClasses)) {
  53. $generatedClassName = $this->checkedClasses[$cacheKey];
  54. assert(is_a($generatedClassName, $className, true));
  55. return $generatedClassName;
  56. }
  57. $proxyParameters = [
  58. 'className' => $className,
  59. 'factory' => static::class,
  60. 'proxyManagerVersion' => Version::getVersion(),
  61. 'proxyOptions' => $proxyOptions,
  62. ];
  63. $proxyClassName = $this
  64. ->configuration
  65. ->getClassNameInflector()
  66. ->getProxyClassName($className, $proxyParameters);
  67. if (! class_exists($proxyClassName)) {
  68. $this->generateProxyClass(
  69. $proxyClassName,
  70. $className,
  71. $proxyParameters,
  72. $proxyOptions
  73. );
  74. }
  75. $this
  76. ->configuration
  77. ->getSignatureChecker()
  78. ->checkSignature(new ReflectionClass($proxyClassName), $proxyParameters);
  79. return $this->checkedClasses[$cacheKey] = $proxyClassName;
  80. }
  81. abstract protected function getGenerator(): ProxyGeneratorInterface;
  82. /**
  83. * Generates the provided `$proxyClassName` from the given `$className` and `$proxyParameters`
  84. *
  85. * @param array<string, mixed> $proxyParameters
  86. * @param array<string, mixed> $proxyOptions
  87. * @psalm-param class-string $proxyClassName
  88. * @psalm-param class-string $className
  89. */
  90. private function generateProxyClass(
  91. string $proxyClassName,
  92. string $className,
  93. array $proxyParameters,
  94. array $proxyOptions = []
  95. ): void {
  96. $className = $this->configuration->getClassNameInflector()->getUserClassName($className);
  97. $phpClass = new ClassGenerator($proxyClassName);
  98. /** @psalm-suppress TooManyArguments - generator interface was not updated due to BC compliance */
  99. $this->getGenerator()->generate(new ReflectionClass($className), $phpClass, $proxyOptions);
  100. $phpClass = $this->configuration->getClassSignatureGenerator()->addSignature($phpClass, $proxyParameters);
  101. /** @psalm-suppress TooManyArguments - generator interface was not updated due to BC compliance */
  102. $this->configuration->getGeneratorStrategy()->generate($phpClass, $proxyOptions);
  103. $autoloader = $this->configuration->getProxyAutoloader();
  104. $autoloader($proxyClassName);
  105. }
  106. }