initial commit
This commit is contained in:
213
vendor/symfony/config/Resource/ReflectionClassResource.php
vendored
Normal file
213
vendor/symfony/config/Resource/ReflectionClassResource.php
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Config\Resource;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ReflectionClassResource implements SelfCheckingResourceInterface
|
||||
{
|
||||
private array $files = [];
|
||||
private string $className;
|
||||
private array $excludedVendors = [];
|
||||
private string $hash;
|
||||
|
||||
public function __construct(
|
||||
private \ReflectionClass $classReflector,
|
||||
array $excludedVendors = [],
|
||||
) {
|
||||
$this->className = $classReflector->name;
|
||||
$this->excludedVendors = $excludedVendors;
|
||||
}
|
||||
|
||||
public function isFresh(int $timestamp): bool
|
||||
{
|
||||
if (!isset($this->hash)) {
|
||||
$this->hash = $this->computeHash();
|
||||
$this->loadFiles($this->classReflector);
|
||||
}
|
||||
|
||||
foreach ($this->files as $file => $v) {
|
||||
if (false === $filemtime = @filemtime($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($filemtime > $timestamp) {
|
||||
return $this->hash === $this->computeHash();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return 'reflection.'.$this->className;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __sleep(): array
|
||||
{
|
||||
if (!isset($this->hash)) {
|
||||
$this->hash = $this->computeHash();
|
||||
$this->loadFiles($this->classReflector);
|
||||
}
|
||||
|
||||
return ['files', 'className', 'hash'];
|
||||
}
|
||||
|
||||
private function loadFiles(\ReflectionClass $class): void
|
||||
{
|
||||
foreach ($class->getInterfaces() as $v) {
|
||||
$this->loadFiles($v);
|
||||
}
|
||||
do {
|
||||
$file = $class->getFileName();
|
||||
if (false !== $file && is_file($file)) {
|
||||
foreach ($this->excludedVendors as $vendor) {
|
||||
if (\in_array($file[\strlen($vendor)] ?? '', ['/', \DIRECTORY_SEPARATOR], true) && str_starts_with($file, $vendor)) {
|
||||
$file = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($file) {
|
||||
$this->files[$file] = null;
|
||||
}
|
||||
}
|
||||
foreach ($class->getTraits() as $v) {
|
||||
$this->loadFiles($v);
|
||||
}
|
||||
} while ($class = $class->getParentClass());
|
||||
}
|
||||
|
||||
private function computeHash(): string
|
||||
{
|
||||
try {
|
||||
$this->classReflector ??= new \ReflectionClass($this->className);
|
||||
} catch (\ReflectionException) {
|
||||
// the class does not exist anymore
|
||||
return false;
|
||||
}
|
||||
$hash = hash_init('xxh128');
|
||||
|
||||
foreach ($this->generateSignature($this->classReflector) as $info) {
|
||||
hash_update($hash, $info);
|
||||
}
|
||||
|
||||
return hash_final($hash);
|
||||
}
|
||||
|
||||
private function generateSignature(\ReflectionClass $class): iterable
|
||||
{
|
||||
$attributes = [];
|
||||
foreach ($class->getAttributes() as $a) {
|
||||
$attributes[] = [$a->getName(), (string) $a];
|
||||
}
|
||||
yield print_r($attributes, true);
|
||||
$attributes = [];
|
||||
|
||||
yield $class->getDocComment() ?: '';
|
||||
yield (int) $class->isFinal();
|
||||
yield (int) $class->isAbstract();
|
||||
|
||||
if ($class->isTrait()) {
|
||||
yield print_r(class_uses($class->name), true);
|
||||
} else {
|
||||
yield print_r(class_parents($class->name), true);
|
||||
yield print_r(class_implements($class->name), true);
|
||||
yield print_r($class->getConstants(), true);
|
||||
}
|
||||
|
||||
foreach ($class->getReflectionConstants() as $constant) {
|
||||
foreach ($constant->getAttributes() as $a) {
|
||||
$attributes[] = [$a->getName(), (string) $a];
|
||||
}
|
||||
yield $constant->name.print_r($attributes, true);
|
||||
$attributes = [];
|
||||
}
|
||||
|
||||
if (!$class->isInterface()) {
|
||||
$defaults = $class->getDefaultProperties();
|
||||
|
||||
foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $p) {
|
||||
foreach ($p->getAttributes() as $a) {
|
||||
$attributes[] = [$a->getName(), (string) $a];
|
||||
}
|
||||
yield print_r($attributes, true);
|
||||
$attributes = [];
|
||||
|
||||
yield $p->getDocComment() ?: '';
|
||||
yield $p->isDefault() ? '<default>' : '';
|
||||
yield $p->isPublic() ? 'public' : 'protected';
|
||||
yield $p->isStatic() ? 'static' : '';
|
||||
yield '$'.$p->name;
|
||||
yield print_r(isset($defaults[$p->name]) && !\is_object($defaults[$p->name]) ? $defaults[$p->name] : null, true);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) {
|
||||
foreach ($this->excludedVendors as $vendor) {
|
||||
$file = $m->getFileName();
|
||||
if (\in_array($file[\strlen($vendor)] ?? '', ['/', \DIRECTORY_SEPARATOR], true) && str_starts_with($file, $vendor)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($m->getAttributes() as $a) {
|
||||
$attributes[] = [$a->getName(), (string) $a];
|
||||
}
|
||||
yield print_r($attributes, true);
|
||||
$attributes = [];
|
||||
|
||||
$defaults = [];
|
||||
foreach ($m->getParameters() as $p) {
|
||||
foreach ($p->getAttributes() as $a) {
|
||||
$attributes[] = [$a->getName(), (string) $a];
|
||||
}
|
||||
yield print_r($attributes, true);
|
||||
$attributes = [];
|
||||
|
||||
if (!$p->isDefaultValueAvailable()) {
|
||||
$defaults[$p->name] = null;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$defaults[$p->name] = (string) $p;
|
||||
}
|
||||
|
||||
yield preg_replace('/^ @@.*/m', '', $m);
|
||||
yield print_r($defaults, true);
|
||||
}
|
||||
|
||||
if ($class->isAbstract() || $class->isInterface() || $class->isTrait()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (interface_exists(EventSubscriberInterface::class, false) && $class->isSubclassOf(EventSubscriberInterface::class)) {
|
||||
yield EventSubscriberInterface::class;
|
||||
yield print_r($class->name::getSubscribedEvents(), true);
|
||||
}
|
||||
|
||||
if (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) {
|
||||
yield ServiceSubscriberInterface::class;
|
||||
yield print_r($class->name::getSubscribedServices(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user