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

  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 array $files = [];
  22.     private string $className;
  23.     private \ReflectionClass $classReflector;
  24.     private array $excludedVendors = [];
  25.     private string $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.     public function isFresh(int $timestamp): bool
  33.     {
  34.         if (!isset($this->hash)) {
  35.             $this->hash $this->computeHash();
  36.             $this->loadFiles($this->classReflector);
  37.         }
  38.         foreach ($this->files as $file => $v) {
  39.             if (false === $filemtime = @filemtime($file)) {
  40.                 return false;
  41.             }
  42.             if ($filemtime $timestamp) {
  43.                 return $this->hash === $this->computeHash();
  44.             }
  45.         }
  46.         return true;
  47.     }
  48.     public function __toString(): string
  49.     {
  50.         return 'reflection.'.$this->className;
  51.     }
  52.     /**
  53.      * @internal
  54.      */
  55.     public function __sleep(): array
  56.     {
  57.         if (!isset($this->hash)) {
  58.             $this->hash $this->computeHash();
  59.             $this->loadFiles($this->classReflector);
  60.         }
  61.         return ['files''className''hash'];
  62.     }
  63.     private function loadFiles(\ReflectionClass $class)
  64.     {
  65.         foreach ($class->getInterfaces() as $v) {
  66.             $this->loadFiles($v);
  67.         }
  68.         do {
  69.             $file $class->getFileName();
  70.             if (false !== $file && is_file($file)) {
  71.                 foreach ($this->excludedVendors as $vendor) {
  72.                     if (str_starts_with($file$vendor) && false !== strpbrk(substr($file\strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) {
  73.                         $file false;
  74.                         break;
  75.                     }
  76.                 }
  77.                 if ($file) {
  78.                     $this->files[$file] = null;
  79.                 }
  80.             }
  81.             foreach ($class->getTraits() as $v) {
  82.                 $this->loadFiles($v);
  83.             }
  84.         } while ($class $class->getParentClass());
  85.     }
  86.     private function computeHash(): string
  87.     {
  88.         try {
  89.             $this->classReflector ??= new \ReflectionClass($this->className);
  90.         } catch (\ReflectionException) {
  91.             // the class does not exist anymore
  92.             return false;
  93.         }
  94.         $hash hash_init('md5');
  95.         foreach ($this->generateSignature($this->classReflector) as $info) {
  96.             hash_update($hash$info);
  97.         }
  98.         return hash_final($hash);
  99.     }
  100.     private function generateSignature(\ReflectionClass $class): iterable
  101.     {
  102.         $attributes = [];
  103.         foreach ($class->getAttributes() as $a) {
  104.             $attributes[] = [$a->getName(), (string) $a];
  105.         }
  106.         yield print_r($attributestrue);
  107.         $attributes = [];
  108.         yield $class->getDocComment();
  109.         yield (int) $class->isFinal();
  110.         yield (int) $class->isAbstract();
  111.         if ($class->isTrait()) {
  112.             yield print_r(class_uses($class->name), true);
  113.         } else {
  114.             yield print_r(class_parents($class->name), true);
  115.             yield print_r(class_implements($class->name), true);
  116.             yield print_r($class->getConstants(), true);
  117.         }
  118.         if (!$class->isInterface()) {
  119.             $defaults $class->getDefaultProperties();
  120.             foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC \ReflectionProperty::IS_PROTECTED) as $p) {
  121.                 foreach ($p->getAttributes() as $a) {
  122.                     $attributes[] = [$a->getName(), (string) $a];
  123.                 }
  124.                 yield print_r($attributestrue);
  125.                 $attributes = [];
  126.                 yield $p->getDocComment();
  127.                 yield $p->isDefault() ? '<default>' '';
  128.                 yield $p->isPublic() ? 'public' 'protected';
  129.                 yield $p->isStatic() ? 'static' '';
  130.                 yield '$'.$p->name;
  131.                 yield print_r(isset($defaults[$p->name]) && !\is_object($defaults[$p->name]) ? $defaults[$p->name] : nulltrue);
  132.             }
  133.         }
  134.         $defined \Closure::bind(static function ($c) { return \defined($c); }, null$class->name);
  135.         foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC \ReflectionMethod::IS_PROTECTED) as $m) {
  136.             foreach ($m->getAttributes() as $a) {
  137.                 $attributes[] = [$a->getName(), (string) $a];
  138.             }
  139.             yield print_r($attributestrue);
  140.             $attributes = [];
  141.             $defaults = [];
  142.             foreach ($m->getParameters() as $p) {
  143.                 foreach ($p->getAttributes() as $a) {
  144.                     $attributes[] = [$a->getName(), (string) $a];
  145.                 }
  146.                 yield print_r($attributestrue);
  147.                 $attributes = [];
  148.                 if (!$p->isDefaultValueAvailable()) {
  149.                     $defaults[$p->name] = null;
  150.                     continue;
  151.                 }
  152.                 $defaults[$p->name] = (string) $p;
  153.             }
  154.             yield preg_replace('/^  @@.*/m'''$m);
  155.             yield print_r($defaultstrue);
  156.         }
  157.         if ($class->isAbstract() || $class->isInterface() || $class->isTrait()) {
  158.             return;
  159.         }
  160.         if (interface_exists(EventSubscriberInterface::class, false) && $class->isSubclassOf(EventSubscriberInterface::class)) {
  161.             yield EventSubscriberInterface::class;
  162.             yield print_r($class->name::getSubscribedEvents(), true);
  163.         }
  164.         if (interface_exists(MessageSubscriberInterface::class, false) && $class->isSubclassOf(MessageSubscriberInterface::class)) {
  165.             yield MessageSubscriberInterface::class;
  166.             foreach ($class->name::getHandledMessages() as $key => $value) {
  167.                 yield $key.print_r($valuetrue);
  168.             }
  169.         }
  170.         if (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) {
  171.             yield ServiceSubscriberInterface::class;
  172.             yield print_r($class->name::getSubscribedServices(), true);
  173.         }
  174.     }
  175. }