Skip to content

Commit

Permalink
* Constants and Properties - collect entire phpDoc, not just the desc…
Browse files Browse the repository at this point in the history
…ription.

* Constants - get type from phpDoc (as we do for properites, and methods)
* New single helper method to get type Constant/Param/Property/Method (return) type
  • Loading branch information
bkdotcom committed Aug 12, 2024
1 parent af62ce1 commit 88aa589
Show file tree
Hide file tree
Showing 23 changed files with 273 additions and 202 deletions.
3 changes: 3 additions & 0 deletions src/Debug/Abstraction/Object/AbstractInheritable.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

use bdk\Debug\Abstraction\AbstractObject;
use ReflectionClass;
use ReflectionClassConstant;
use ReflectionProperty;
use Reflector;

/**
* Base class for collecting constants, properties, & methods
Expand Down
38 changes: 26 additions & 12 deletions src/Debug/Abstraction/Object/Constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@ class Constants extends AbstractInheritable
'declaredLast' => null,
'declaredOrig' => null,
'declaredPrev' => null,
'desc' => '',
'isFinal' => false,
'phpDoc' => array(
'desc' => '',
'summary' => '',
),
'type' => null,
'value' => null,
'visibility' => 'public',
Expand Down Expand Up @@ -108,6 +111,18 @@ public function addCases(Abstraction $abs)
$abs['cases'] = $cases;
}

/**
* Build constant info by passing values
*
* @param array $values Values to apply
*
* @return array
*/
public static function buildValues($values = array())
{
return \array_merge(static::$baseConstInfo, $values);
}

/**
* Get constants (php < 7.1)
*
Expand All @@ -121,7 +136,7 @@ private function addConstantsLegacy(ReflectionClass $reflector)
foreach ($reflector->getConstants() as $name => $value) {
$info = isset($this->constants[$name])
? $this->constants[$name]
: \array_merge(static::$baseConstInfo, array('value' => $value));
: static::buildValues(array('value' => $value));
// no reflection... unable to determine declaredLast & declaredPrev
$info['declaredOrig'] = $className;
$this->constants[$name] = $info;
Expand Down Expand Up @@ -166,14 +181,14 @@ private function addConstantsReflection(ReflectionClass $reflector)
*/
private function getCaseRefInfo(ReflectionEnumUnitCase $refCase)
{
$phpDoc = $this->helper->getPhpDocVar($refCase);
unset($phpDoc['type']);
return array(
'attributes' => $this->attributeCollect
? $this->helper->getAttributes($refCase)
: array(),
'desc' => $this->phpDocCollect
? $this->helper->getPhpDocVar($refCase)['desc'] // actually the summary
: '',
'isFinal' => $refCase->isFinal(),
'phpDoc' => $phpDoc,
'value' => $refCase instanceof ReflectionEnumBackedCase
? $refCase->getBackingValue()
: Abstracter::UNDEFINED,
Expand All @@ -194,19 +209,18 @@ private function getConstantRefInfo(ReflectionClassConstant $refConstant)
if ($value instanceof UnitEnum) {
$value = $this->abstracter->crate($value, $this->abs['debugMethod']);
}
return \array_merge(static::$baseConstInfo, array(
$phpDoc = $this->helper->getPhpDocVar($refConstant, $this->abs['fullyQualifyPhpDocType']);
$type = $this->helper->getType($phpDoc['type'], $refConstant);
unset($phpDoc['type']);
return static::buildValues(array(
'attributes' => $this->attributeCollect
? $this->helper->getAttributes($refConstant)
: array(),
'desc' => $this->phpDocCollect
? $this->helper->getPhpDocVar($refConstant)['desc'] // actually the summary
: '',
'isFinal' => PHP_VERSION_ID >= 80100
? $refConstant->isFinal()
: false,
'type' => PHP_VERSION_ID >= 80300
? $this->helper->getTypeString($refConstant->getType())
: null,
'phpDoc' => $phpDoc,
'type' => $type,
'value' => $value,
'visibility' => $this->helper->getVisibility($refConstant),
));
Expand Down
116 changes: 74 additions & 42 deletions src/Debug/Abstraction/Object/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
use bdk\Debug\Utility\PhpDoc;
use ReflectionAttribute;
use ReflectionClass;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionParameter;
use ReflectionProperty;
use ReflectionType;
use Reflector;

Expand Down Expand Up @@ -103,30 +105,6 @@ public static function getClassName(ReflectionClass $reflector)
: $reflector->getName();
}

/**
* Get param type
*
* @param ReflectionParameter $refParameter reflectionParameter
*
* @return string|null
*/
public static function getParamType(ReflectionParameter $refParameter)
{
if (PHP_VERSION_ID >= 70000) {
return self::getTypeString($refParameter->getType());
}
if ($refParameter->isArray()) {
// isArray is deprecated in php 8.0
// isArray is only concerned with type-hint and does not look at default value
return 'array';
}
if (\preg_match('/\[\s<\w+>\s([\w\\\\]+)/s', $refParameter->__toString(), $matches)) {
// Parameter #0 [ <required> namespace\Type $varName ]
return $matches[1];
}
return null;
}

/**
* Get parsed PhpDoc
*
Expand All @@ -141,9 +119,9 @@ public function getPhpDoc(Reflector $reflector, $fullyQualifyType = false)
}

/**
* Get type and description from phpDoc comment for Constant or Property
* Get type and description from phpDoc comment for Constant, Case, or Property
*
* @param Reflector $reflector ReflectionProperty or ReflectionClassConstant property object
* @param Reflector $reflector ReflectionClassConstant, ReflectionEnumUnitCase, or ReflectionProperty
* @param bool $fullyQualifyType Whether to further parse / resolve types
*
* @return array
Expand All @@ -152,31 +130,35 @@ public function getPhpDocVar(Reflector $reflector, $fullyQualifyType = false)
{
/** @psalm-suppress NoInterfaceProperties */
$name = $reflector->name;
$phpDoc = $this->getPhpDoc($reflector, $fullyQualifyType);
$info = array(
'desc' => $phpDoc['summary'],
$phpDoc = \array_merge(array(
'desc' => '',
'summary' => '',
'type' => null,
'var' => array(),
), $this->getPhpDoc($reflector, $fullyQualifyType));
$foundVar = array(
'desc' => '',
'type' => null,
);
if (isset($phpDoc['var']) === false) {
return $info;
}
/*
php's getDocComment doesn't play nice with compound statements
https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/var.html
https://github.com/php-fig/fig-standards/blob/master/proposed/phpdoc-tags.md#518-var
@todo check other constants/properties for matching @var tag
*/
$var = array();
foreach ($phpDoc['var'] as $var) {
if ($var['name'] === $name) {
break;
$foundVar = $var;
}
}
$info['type'] = $var['type'];
if (!$info['desc']) {
$info['desc'] = $var['desc'];
} elseif ($var['desc']) {
$info['desc'] = $info['desc'] . ': ' . $var['desc'];
unset($phpDoc['var']);
$phpDoc['type'] = $foundVar['type'];
if (!$phpDoc['summary']) {
$phpDoc['summary'] = $foundVar['desc'];
} elseif ($foundVar['desc']) {
$phpDoc['summary'] = \trim($phpDoc['summary'] . "\n\n" . $foundVar['desc']);
}
return $info;
return $phpDoc;
}

/**
Expand Down Expand Up @@ -214,14 +196,43 @@ public static function getVisibility(Reflector $reflector)
return 'public';
}

/**
* Get Constant, Property, or Parameter's type or Method's return type
* Priority given to phpDoc type, followed by reflection type (if available)
*
* @param string $phpDocType Type specified in phpDoc block
* @param ReflectionClassConstant|ReflectionMethod|ReflectionParameter|ReflectionProperty $reflector ClassConstant, Method, Parameter, or Property Reflector instance
*
* @return string|null
*/
public static function getType($phpDocType, Reflector $reflector)
{
if ($phpDocType !== null) {
return $phpDocType;
}
if (\method_exists($reflector, 'getType')) {
// ReflectionClassConstant : php >= 8.3
// ReflectionParameter : php >= 7.0
// ReflectionProperty : php >= 7.4
return static::getTypeString($reflector->getType());
}
if ($reflector instanceof ReflectionMethod && PHP_VERSION_ID >= 70000) {
return static::getTypeString($reflector->getReturnType());
}
if ($reflector instanceof ReflectionParameter) {
return static::getParamTypeOld($reflector);
}
return null;
}

/**
* Get string representation of ReflectionNamedType or ReflectionType
*
* @param ReflectionType|null $type ReflectionType
*
* @return string|null
*/
public static function getTypeString(ReflectionType $type = null)
protected static function getTypeString(ReflectionType $type = null)
{
if ($type === null) {
return null;
Expand All @@ -230,4 +241,25 @@ public static function getTypeString(ReflectionType $type = null)
? $type->getName()
: (string) $type;
}

/**
* Get parameter type from ReflectionParameter for PHP < 7.0
*
* @param ReflectionParameter $reflector ReflectionParameter instance
*
* @return string|null
*/
protected static function getParamTypeOld(ReflectionParameter $reflector)
{
if ($reflector->isArray()) {
// isArray is deprecated in php 8.0
// isArray is only concerned with type-hint and does not look at default value
return 'array';
}
if (\preg_match('/\[\s<\w+>\s([\w\\\\]+)/s', $reflector->__toString(), $matches)) {
// Parameter #0 [ <required> namespace\Type $varName ]
return $matches[1];
}
return null;
}
}
17 changes: 1 addition & 16 deletions src/Debug/Abstraction/Object/MethodParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ private function getParamsReflection(ReflectionMethod $refMethod, array $phpDocP
? $refParameter->isVariadic() || $phpDocParam['isVariadic']
: $phpDocParam['isVariadic'],
'name' => $name,
'type' => $this->getParamTypeHint($refParameter, $phpDocParam['type']),
'type' => $this->helper->getType($phpDocParam['type'], $refParameter),
));
}
\restore_error_handler();
Expand Down Expand Up @@ -228,21 +228,6 @@ private function getConstantName(ReflectionParameter $refParameter)
return $name;
}

/**
* Get param type-hint
*
* @param ReflectionParameter $refParameter reflectionParameter
* @param string|null $phpDocType param's phpdoc type
*
* @return string|null
*/
private function getParamTypeHint(ReflectionParameter $refParameter, $phpDocType)
{
return $phpDocType !== null
? $phpDocType
: $this->helper->getParamType($refParameter);
}

/**
* Build default value via PhpDoc
*
Expand Down
42 changes: 12 additions & 30 deletions src/Debug/Abstraction/Object/Methods.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public function addInstance(Abstraction $abs)
*
* @return array
*/
public static function buildMethodValues(array $values = array())
public static function buildValues(array $values = array())
{
return \array_merge(static::$baseMethodInfo, $values);
}
Expand Down Expand Up @@ -256,7 +256,7 @@ private function addViaPhpDocBuild(Abstraction $abs, array $phpDoc, $declaredLas
$className = $declaredLast
? $declaredLast
: $abs['className'];
return $this->buildMethodValues(array(
return static::buildValues(array(
'declaredLast' => $declaredLast,
'isStatic' => $phpDoc['static'],
'params' => $this->params->getParamsPhpDoc($abs, $phpDoc, $className),
Expand Down Expand Up @@ -355,8 +355,6 @@ private function addViaRefBuild(Abstraction $abs, ReflectionMethod $refMethod, $
$this->methodsWithStatic[] = $name;
}
unset($info['hasStaticVars']);
unset($info['phpDoc']['param']);
unset($info['phpDoc']['return']);
$this->methods[$name] = $info;
}

Expand All @@ -371,7 +369,11 @@ private function addViaRefBuild(Abstraction $abs, ReflectionMethod $refMethod, $
private function addViaRefBuildInit(Abstraction $abs, ReflectionMethod $refMethod)
{
$phpDoc = $this->helper->getPhpDoc($refMethod, $abs['fullyQualifyPhpDocType']);
return $this->buildMethodValues(array(
$returnTag = isset($phpDoc['return']) ? $phpDoc['return'] : array(
'desc' => '',
'type' => null,
);
return static::buildValues(array(
'attributes' => $abs['cfgFlags'] & AbstractObject::METHOD_ATTRIBUTE_COLLECT
? $this->helper->getAttributes($refMethod)
: array(),
Expand All @@ -381,32 +383,12 @@ private function addViaRefBuildInit(Abstraction $abs, ReflectionMethod $refMetho
'isFinal' => $refMethod->isFinal(),
'isStatic' => $refMethod->isStatic(),
'params' => $this->params->getParams($abs, $refMethod, $phpDoc),
'phpDoc' => $phpDoc,
'return' => $this->getReturn($refMethod, $phpDoc),
'phpDoc' => \array_diff_key($phpDoc, \array_flip(array('param', 'return'))),
'return' => array(
'desc' => $returnTag['desc'],
'type' => $this->helper->getType($returnTag['type'], $refMethod),
),
'visibility' => $this->helper->getVisibility($refMethod),
));
}

/**
* Get return type & desc
*
* @param ReflectionMethod $refMethod ReflectionMethod
* @param array $phpDoc parsed phpDoc param info
*
* @return array
*/
private function getReturn(ReflectionMethod $refMethod, array $phpDoc)
{
$return = array(
'desc' => '',
'type' => null,
);
if (isset($phpDoc['return']['type'])) {
return \array_merge($return, $phpDoc['return']);
}
if (PHP_VERSION_ID >= 70000) {
$return['type'] = $this->helper->getTypeString($refMethod->getReturnType());
}
return $return;
}
}
Loading

0 comments on commit 88aa589

Please sign in to comment.