123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- <?php
- declare(strict_types=1);
- /**
- * This file is part of the Carbon package.
- *
- * (c) Brian Nesbitt <brian@nesbot.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Carbon\PHPStan;
- use Closure;
- use InvalidArgumentException;
- use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter as AdapterReflectionParameter;
- use PHPStan\BetterReflection\Reflection\Adapter\ReflectionType as AdapterReflectionType;
- use PHPStan\BetterReflection\Reflection\ReflectionClass as BetterReflectionClass;
- use PHPStan\BetterReflection\Reflection\ReflectionFunction as BetterReflectionFunction;
- use PHPStan\BetterReflection\Reflection\ReflectionParameter as BetterReflectionParameter;
- use PHPStan\Reflection\Php\BuiltinMethodReflection;
- use PHPStan\TrinaryLogic;
- use ReflectionClass;
- use ReflectionFunction;
- use ReflectionMethod;
- use ReflectionParameter;
- use ReflectionType;
- use stdClass;
- use Throwable;
- abstract class AbstractMacro implements BuiltinMethodReflection
- {
- /**
- * The reflection function/method.
- *
- * @var ReflectionFunction|ReflectionMethod
- */
- protected $reflectionFunction;
- /**
- * The class name.
- *
- * @var class-string
- */
- private $className;
- /**
- * The method name.
- *
- * @var string
- */
- private $methodName;
- /**
- * The parameters.
- *
- * @var ReflectionParameter[]
- */
- private $parameters;
- /**
- * The is static.
- *
- * @var bool
- */
- private $static = false;
- /**
- * Macro constructor.
- *
- * @param class-string $className
- * @param string $methodName
- * @param callable $macro
- */
- public function __construct(string $className, string $methodName, $macro)
- {
- $this->className = $className;
- $this->methodName = $methodName;
- $rawReflectionFunction = \is_array($macro)
- ? new ReflectionMethod($macro[0], $macro[1])
- : new ReflectionFunction($macro);
- $this->reflectionFunction = self::hasModernParser()
- ? $this->getReflectionFunction($macro)
- : $rawReflectionFunction; // @codeCoverageIgnore
- $this->parameters = array_map(
- function ($parameter) {
- if ($parameter instanceof BetterReflectionParameter) {
- return new AdapterReflectionParameter($parameter);
- }
- return $parameter; // @codeCoverageIgnore
- },
- $this->reflectionFunction->getParameters()
- );
- if ($rawReflectionFunction->isClosure()) {
- try {
- $closure = $rawReflectionFunction->getClosure();
- $boundClosure = Closure::bind($closure, new stdClass());
- $this->static = (!$boundClosure || (new ReflectionFunction($boundClosure))->getClosureThis() === null);
- } catch (Throwable $e) {
- $this->static = true;
- }
- }
- }
- private function getReflectionFunction($spec)
- {
- if (\is_array($spec) && \count($spec) === 2 && \is_string($spec[1])) {
- \assert($spec[1] !== '');
- if (\is_object($spec[0])) {
- return BetterReflectionClass::createFromInstance($spec[0])
- ->getMethod($spec[1]);
- }
- return BetterReflectionClass::createFromName($spec[0])
- ->getMethod($spec[1]);
- }
- if (\is_string($spec)) {
- return BetterReflectionFunction::createFromName($spec);
- }
- if ($spec instanceof Closure) {
- return BetterReflectionFunction::createFromClosure($spec);
- }
- throw new InvalidArgumentException('Could not create reflection from the spec given'); // @codeCoverageIgnore
- }
- /**
- * {@inheritdoc}
- */
- public function getDeclaringClass(): ReflectionClass
- {
- return new ReflectionClass($this->className);
- }
- /**
- * {@inheritdoc}
- */
- public function isPrivate(): bool
- {
- return false;
- }
- /**
- * {@inheritdoc}
- */
- public function isPublic(): bool
- {
- return true;
- }
- /**
- * {@inheritdoc}
- */
- public function isFinal(): bool
- {
- return false;
- }
- /**
- * {@inheritdoc}
- */
- public function isInternal(): bool
- {
- return false;
- }
- /**
- * {@inheritdoc}
- */
- public function isAbstract(): bool
- {
- return false;
- }
- /**
- * {@inheritdoc}
- */
- public function isStatic(): bool
- {
- return $this->static;
- }
- /**
- * {@inheritdoc}
- */
- public function getDocComment(): ?string
- {
- return $this->reflectionFunction->getDocComment() ?: null;
- }
- /**
- * {@inheritdoc}
- */
- public function getName(): string
- {
- return $this->methodName;
- }
- /**
- * {@inheritdoc}
- */
- public function getParameters(): array
- {
- return $this->parameters;
- }
- /**
- * {@inheritdoc}
- */
- public function getReturnType(): ?ReflectionType
- {
- $type = $this->reflectionFunction->getReturnType();
- if ($type instanceof ReflectionType) {
- return $type; // @codeCoverageIgnore
- }
- return self::adaptType($type);
- }
- /**
- * {@inheritdoc}
- */
- public function isDeprecated(): TrinaryLogic
- {
- return TrinaryLogic::createFromBoolean(
- $this->reflectionFunction->isDeprecated() ||
- preg_match('/@deprecated/i', $this->getDocComment() ?: '')
- );
- }
- /**
- * {@inheritdoc}
- */
- public function isVariadic(): bool
- {
- return $this->reflectionFunction->isVariadic();
- }
- /**
- * {@inheritdoc}
- */
- public function getPrototype(): BuiltinMethodReflection
- {
- return $this;
- }
- public function getTentativeReturnType(): ?ReflectionType
- {
- return null;
- }
- public function returnsByReference(): TrinaryLogic
- {
- return TrinaryLogic::createNo();
- }
- private static function adaptType($type)
- {
- $method = method_exists(AdapterReflectionType::class, 'fromTypeOrNull')
- ? 'fromTypeOrNull'
- : 'fromReturnTypeOrNull'; // @codeCoverageIgnore
- return AdapterReflectionType::$method($type);
- }
- private static function hasModernParser(): bool
- {
- static $modernParser = null;
- if ($modernParser !== null) {
- return $modernParser;
- }
- $modernParser = method_exists(AdapterReflectionType::class, 'fromTypeOrNull');
- return $modernParser;
- }
- }
|