vendor/symfony/config/Resource/ReflectionClassResource.php line 107

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Config\Resource;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
  13. use Symfony\Contracts\Service\ServiceSubscriberInterface;
  14. /**
  15.  * @author Nicolas Grekas <p@tchwork.com>
  16.  *
  17.  * @final
  18.  */
  19. class ReflectionClassResource implements SelfCheckingResourceInterface
  20. {
  21.     private $files = [];
  22.     private $className;
  23.     private $classReflector;
  24.     private $excludedVendors = [];
  25.     private $hash;
  26.     public function __construct(\ReflectionClass $classReflector, array $excludedVendors = [])
  27.     {
  28.         $this->className $classReflector->name;
  29.         $this->classReflector $classReflector;
  30.         $this->excludedVendors $excludedVendors;
  31.     }
  32.     /**
  33.      * {@inheritdoc}
  34.      */
  35.     public function isFresh(int $timestamp): bool
  36.     {
  37.         if (null === $this->hash) {
  38.             $this->hash $this->computeHash();
  39.             $this->loadFiles($this->classReflector);
  40.         }
  41.         foreach ($this->files as $file => $v) {
  42.             if (false === $filemtime = @filemtime($file)) {
  43.                 return false;
  44.             }
  45.             if ($filemtime $timestamp) {
  46.                 return $this->hash === $this->computeHash();
  47.             }
  48.         }
  49.         return true;
  50.     }
  51.     public function __toString(): string
  52.     {
  53.         return 'reflection.'.$this->className;
  54.     }
  55.     /**
  56.      * @internal
  57.      */
  58.     public function __sleep(): array
  59.     {
  60.         if (null === $this->hash) {
  61.             $this->hash $this->computeHash();
  62.             $this->loadFiles($this->classReflector);
  63.         }
  64.         return ['files''className''hash'];
  65.     }
  66.     private function loadFiles(\ReflectionClass $class)
  67.     {
  68.         foreach ($class->getInterfaces() as $v) {
  69.             $this->loadFiles($v);
  70.         }
  71.         do {
  72.             $file $class->getFileName();
  73.             if (false !== $file && is_file($file)) {
  74.                 foreach ($this->excludedVendors as $vendor) {
  75.                     if (str_starts_with($file$vendor) && false !== strpbrk(substr($file\strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) {
  76.                         $file false;
  77.                         break;
  78.                     }
  79.                 }
  80.                 if ($file) {
  81.                     $this->files[$file] = null;
  82.                 }
  83.             }
  84.             foreach ($class->getTraits() as $v) {
  85.                 $this->loadFiles($v);
  86.             }
  87.         } while ($class $class->getParentClass());
  88.     }
  89.     private function computeHash(): string
  90.     {
  91.         if (null === $this->classReflector) {
  92.             try {
  93.                 $this->classReflector = new \ReflectionClass($this->className);
  94.             } catch (\ReflectionException $e) {
  95.                 // the class does not exist anymore
  96.                 return false;
  97.             }
  98.         }
  99.         $hash hash_init('md5');
  100.         foreach ($this->generateSignature($this->classReflector) as $info) {
  101.             hash_update($hash$info);
  102.         }
  103.         return hash_final($hash);
  104.     }
  105.     private function generateSignature(\ReflectionClass $class): iterable
  106.     {
  107.         if (\PHP_VERSION_ID >= 80000) {
  108.             $attributes = [];
  109.             foreach ($class->getAttributes() as $a) {
  110.                 $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a $a->getArguments()];
  111.             }
  112.             yield print_r($attributestrue);
  113.             $attributes = [];
  114.         }
  115.         yield $class->getDocComment();
  116.         yield (int) $class->isFinal();
  117.         yield (int) $class->isAbstract();
  118.         if ($class->isTrait()) {
  119.             yield print_r(class_uses($class->name), true);
  120.         } else {
  121.             yield print_r(class_parents($class->name), true);
  122.             yield print_r(class_implements($class->name), true);
  123.             yield print_r($class->getConstants(), true);
  124.         }
  125.         if (!$class->isInterface()) {
  126.             $defaults $class->getDefaultProperties();
  127.             foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC \ReflectionProperty::IS_PROTECTED) as $p) {
  128.                 if (\PHP_VERSION_ID >= 80000) {
  129.                     foreach ($p->getAttributes() as $a) {
  130.                         $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a $a->getArguments()];
  131.                     }
  132.                     yield print_r($attributestrue);
  133.                     $attributes = [];
  134.                 }
  135.                 yield $p->getDocComment();
  136.                 yield $p->isDefault() ? '<default>' '';
  137.                 yield $p->isPublic() ? 'public' 'protected';
  138.                 yield $p->isStatic() ? 'static' '';
  139.                 yield '$'.$p->name;
  140.                 yield print_r(isset($defaults[$p->name]) && !\is_object($defaults[$p->name]) ? $defaults[$p->name] : nulltrue);
  141.             }
  142.         }
  143.         $defined \Closure::bind(static function ($c) { return \defined($c); }, null$class->name);
  144.         foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC \ReflectionMethod::IS_PROTECTED) as $m) {
  145.             if (\PHP_VERSION_ID >= 80000) {
  146.                 foreach ($m->getAttributes() as $a) {
  147.                     $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a $a->getArguments()];
  148.                 }
  149.                 yield print_r($attributestrue);
  150.                 $attributes = [];
  151.             }
  152.             $defaults = [];
  153.             $parametersWithUndefinedConstants = [];
  154.             foreach ($m->getParameters() as $p) {
  155.                 if (\PHP_VERSION_ID >= 80000) {
  156.                     foreach ($p->getAttributes() as $a) {
  157.                         $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a $a->getArguments()];
  158.                     }
  159.                     yield print_r($attributestrue);
  160.                     $attributes = [];
  161.                 }
  162.                 if (!$p->isDefaultValueAvailable()) {
  163.                     $defaults[$p->name] = null;
  164.                     continue;
  165.                 }
  166.                 if (\PHP_VERSION_ID >= 80100) {
  167.                     $defaults[$p->name] = (string) $p;
  168.                     continue;
  169.                 }
  170.                 if (!$p->isDefaultValueConstant() || $defined($p->getDefaultValueConstantName())) {
  171.                     $defaults[$p->name] = $p->getDefaultValue();
  172.                     continue;
  173.                 }
  174.                 $defaults[$p->name] = $p->getDefaultValueConstantName();
  175.                 $parametersWithUndefinedConstants[$p->name] = true;
  176.             }
  177.             if (!$parametersWithUndefinedConstants) {
  178.                 yield preg_replace('/^  @@.*/m'''$m);
  179.             } else {
  180.                 $t $m->getReturnType();
  181.                 $stack = [
  182.                     $m->getDocComment(),
  183.                     $m->getName(),
  184.                     $m->isAbstract(),
  185.                     $m->isFinal(),
  186.                     $m->isStatic(),
  187.                     $m->isPublic(),
  188.                     $m->isPrivate(),
  189.                     $m->isProtected(),
  190.                     $m->returnsReference(),
  191.                     $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t,
  192.                 ];
  193.                 foreach ($m->getParameters() as $p) {
  194.                     if (!isset($parametersWithUndefinedConstants[$p->name])) {
  195.                         $stack[] = (string) $p;
  196.                     } else {
  197.                         $t $p->getType();
  198.                         $stack[] = $p->isOptional();
  199.                         $stack[] = $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t;
  200.                         $stack[] = $p->isPassedByReference();
  201.                         $stack[] = $p->isVariadic();
  202.                         $stack[] = $p->getName();
  203.                     }
  204.                 }
  205.                 yield implode(','$stack);
  206.             }
  207.             yield print_r($defaultstrue);
  208.         }
  209.         if ($class->isAbstract() || $class->isInterface() || $class->isTrait()) {
  210.             return;
  211.         }
  212.         if (interface_exists(EventSubscriberInterface::class, false) && $class->isSubclassOf(EventSubscriberInterface::class)) {
  213.             yield EventSubscriberInterface::class;
  214.             yield print_r($class->name::getSubscribedEvents(), true);
  215.         }
  216.         if (interface_exists(MessageSubscriberInterface::class, false) && $class->isSubclassOf(MessageSubscriberInterface::class)) {
  217.             yield MessageSubscriberInterface::class;
  218.             foreach ($class->name::getHandledMessages() as $key => $value) {
  219.                 yield $key.print_r($valuetrue);
  220.             }
  221.         }
  222.         if (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) {
  223.             yield ServiceSubscriberInterface::class;
  224.             yield print_r($class->name::getSubscribedServices(), true);
  225.         }
  226.     }
  227. }