Skip to content

Commit

Permalink
Enum: improve output when enum is method param default value
Browse files Browse the repository at this point in the history
  • Loading branch information
bkdotcom committed Aug 1, 2022
1 parent d39cc49 commit 195e730
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 65 deletions.
12 changes: 10 additions & 2 deletions src/Debug/Abstraction/AbstractObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,6 @@ private function absClean(Abstraction $abs)
'collectPropertyValues',
'fullyQualifyPhpDocType',
'hist',
// 'isAnonymous',
'isTraverseOnly',
'propertyOverrideValues',
'reflector',
Expand Down Expand Up @@ -455,9 +454,18 @@ private function doAbstraction(Abstraction $abs)
private function getCfgFlags()
{
$flagVals = \array_intersect_key(self::$cfgFlags, \array_filter($this->cfg));
return \array_reduce($flagVals, function ($carry, $val) {
$bitmask = \array_reduce($flagVals, function ($carry, $val) {
return $carry | $val;
}, 0);
if ($bitmask & self::BRIEF) {
$bitmask &= ~self::CASE_COLLECT;
$bitmask &= ~self::CONST_COLLECT;
$bitmask &= ~self::METHOD_COLLECT;
$bitmask &= ~self::OBJ_ATTRIBUTE_COLLECT;
$bitmask &= ~self::PROP_ATTRIBUTE_COLLECT;
$bitmask &= ~self::TO_STRING_OUTPUT;
}
return $bitmask;
}

/**
Expand Down
12 changes: 9 additions & 3 deletions src/Debug/Abstraction/AbstractObjectMethodParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
use bdk\Debug\Abstraction\AbstractObjectHelper;
use ReflectionMethod;
use ReflectionParameter;
use UnitEnum;

/**
* Get method parameter info
*/
class AbstractObjectMethodParams
{
protected $abs;
protected $abstracter;
protected $helper;

private static $baseParamInfo = array(
Expand All @@ -40,10 +42,12 @@ class AbstractObjectMethodParams
/**
* Constructor
*
* @param AbstractObjectHelper $helper helper class
* @param Abstracter $abstracter Abstracter
* @param AbstractObjectHelper $helper helper class
*/
public function __construct(AbstractObjectHelper $helper)
public function __construct(Abstracter $abstracter, AbstractObjectHelper $helper)
{
$this->abstracter = $abstracter;
$this->helper = $helper;
}

Expand Down Expand Up @@ -179,7 +183,9 @@ private function getParamDefaultVal(ReflectionParameter $refParameter)
$defaultValue = Abstracter::UNDEFINED;
if ($refParameter->isDefaultValueAvailable()) {
$defaultValue = $refParameter->getDefaultValue();
if (PHP_VERSION_ID >= 50406 && $refParameter->isDefaultValueConstant()) {
if ($defaultValue instanceof UnitEnum) {
$defaultValue = $this->abstracter->crate($defaultValue, $this->abs['debugMethod']);
} elseif (PHP_VERSION_ID >= 50406 && $refParameter->isDefaultValueConstant()) {
/*
getDefaultValueConstantName() :
php may return something like self::CONSTANT_NAME
Expand Down
119 changes: 66 additions & 53 deletions src/Debug/Abstraction/AbstractObjectMethods.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
*/
class AbstractObjectMethods
{
protected $abs;
protected $abstracter;
protected $helper;
protected $params;
Expand Down Expand Up @@ -62,7 +61,7 @@ public function __construct(Abstracter $abstracter, AbstractObjectHelper $helper
{
$this->abstracter = $abstracter;
$this->helper = $helper;
$this->params = new AbstractObjectMethodParams($helper);
$this->params = new AbstractObjectMethodParams($abstracter, $helper);
}

/**
Expand All @@ -77,11 +76,10 @@ public function add(Abstraction $abs)
if ($abs['isTraverseOnly']) {
return;
}
$this->abs = $abs;
$abs['cfgFlags'] & AbstractObject::METHOD_COLLECT
? $this->addMethodsFull()
: $this->addMethodsMin();
$this->addFinish();
? $this->addMethodsFull($abs)
: $this->addMethodsMin($abs);
$this->addFinish($abs);
}

/**
Expand All @@ -99,19 +97,22 @@ public static function buildMethodValues($values = array())
/**
* Adds methods to abstraction
*
* @param Abstraction $abs Object Abstraction instance
*
* @return void
*/
private function addMethodsFull()
private function addMethodsFull(Abstraction $abs)
{
$abs = $this->abs;
if ($this->abstracter->getCfg('methodCache') && isset(static::$methodCache[$abs['className']])) {
$abs['methods'] = static::$methodCache[$abs['className']];
$this->addFinish();
$this->addFinish($abs);
return;
}
$this->addViaReflection();
$this->addViaPhpDoc();
$this->addImplements();
$briefBak = $this->abstracter->debug->setCfg('brief', true);
$this->addViaReflection($abs);
$this->abstracter->debug->setCfg('brief', $briefBak);
$this->addViaPhpDoc($abs);
$this->addImplements($abs);
if ($abs['className'] !== 'Closure') {
static::$methodCache[$abs['className']] = $abs['methods'];
}
Expand All @@ -120,11 +121,12 @@ private function addMethodsFull()
/**
* Add minimal method information to abstraction
*
* @param Abstraction $abs Object Abstraction instance
*
* @return void
*/
private function addMethodsMin()
private function addMethodsMin(Abstraction $abs)
{
$abs = $this->abs;
$obj = $abs->getSubject();
if (\method_exists($obj, '__toString')) {
$abs['methods']['__toString'] = array(
Expand All @@ -143,16 +145,17 @@ private function addMethodsMin()
/**
* remove phpDoc[method]
*
* @param Abstraction $abs Object Abstraction instance
*
* @return void
*/
private function addFinish()
private function addFinish(Abstraction $abs)
{
$abs = $this->abs;
unset($abs['phpDoc']['method']);
if (isset($abs['methods']['__toString'])) {
$abs['methods']['__toString']['returnValue'] = $this->toString();
$abs['methods']['__toString']['returnValue'] = $this->toString($abs);
}
$phpDocCollect = $this->abs['cfgFlags'] & AbstractObject::PHPDOC_COLLECT;
$phpDocCollect = $abs['cfgFlags'] & AbstractObject::PHPDOC_COLLECT;
if ($phpDocCollect) {
return;
}
Expand All @@ -170,11 +173,12 @@ private function addFinish()
/**
* Add `implements` value to common interface methods
*
* @param Abstraction $abs Object Abstraction instance
*
* @return void
*/
private function addImplements()
private function addImplements(Abstraction $abs)
{
$abs = $this->abs;
$interfaceMethods = array(
'ArrayAccess' => array('offsetExists','offsetGet','offsetSet','offsetUnset'),
'BackedEnum' => array('from', 'tryFrom'),
Expand All @@ -196,45 +200,48 @@ private function addImplements()
* "Magic" methods may be defined in a class' doc-block
* If so... move this information to method info
*
* @param Abstraction $abs Object Abstraction instance
*
* @return void
*
* @see http://docs.phpdoc.org/references/phpdoc/tags/method.html
*/
private function addViaPhpDoc()
private function addViaPhpDoc(Abstraction $abs)
{
$abs = $this->abs;
$inheritedFrom = null;
if (
empty($abs['phpDoc']['method'])
&& \array_intersect_key($abs['methods'], \array_flip(array('__call', '__callStatic')))
) {
// phpDoc doesn't contain any @method tags,
// we've got __call and/or __callStatic method: check if parent classes have @method tags
$inheritedFrom = $this->addViaPhpDocInherit();
$inheritedFrom = $this->addViaPhpDocInherit($abs);
}
if (empty($abs['phpDoc']['method'])) {
// still undefined or empty
return;
}
foreach ($abs['phpDoc']['method'] as $phpDocMethod) {
$abs['methods'][$phpDocMethod['name']] = $this->buildMethodPhpDoc($phpDocMethod, $inheritedFrom);
$abs['methods'][$phpDocMethod['name']] = $this->buildMethodPhpDoc($abs, $phpDocMethod, $inheritedFrom);
}
}

/**
* Inspect inherited classes until we find methods defined in PhpDoc
*
* @param Abstraction $abs Object Abstraction instance
*
* @return string|null class where found
*/
private function addViaPhpDocInherit()
private function addViaPhpDocInherit(Abstraction $abs)
{
$inheritedFrom = null;
$reflector = $this->abs['reflector'];
$reflector = $abs['reflector'];
while ($reflector = $reflector->getParentClass()) {
$parsed = $this->helper->getPhpDoc($reflector);
if (isset($parsed['method'])) {
$inheritedFrom = $reflector->getName();
$this->abs['phpDoc']['method'] = $parsed['method'];
$abs['phpDoc']['method'] = $parsed['method'];
break;
}
}
Expand All @@ -244,19 +251,22 @@ private function addViaPhpDocInherit()
/**
* Add methods from reflection
*
* @param Abstraction $abs Object Abstraction instance
*
* @return void
*/
private function addViaReflection()
private function addViaReflection(Abstraction $abs)
{
$abs = $this->abs;
$obj = $abs->getSubject();
$methods = array();
foreach ($abs['reflector']->getMethods() as $refMethod) {
$info = $this->buildMethodRef($obj, $refMethod);
$info = $this->buildMethodRef($abs, $refMethod);
if ($info['visibility'] === 'private' && $info['inheritedFrom']) {
// getMethods() returns parent's private methods (#reasons).. we'll skip it
continue;
}
unset($info['phpDoc']['param']);
unset($info['phpDoc']['return']);
\ksort($info['phpDoc']);
$methodName = $refMethod->getName();
$methods[$methodName] = $info;
}
Expand All @@ -266,27 +276,28 @@ private function addViaReflection()
/**
* Build magic method info
*
* @param array $phpDocMethod parsed phpdoc method info
* @param string $inheritedFrom classname or null
* @param Abstraction $abs Object Abstraction instance
* @param array $phpDocMethod parsed phpdoc method info
* @param string $inheritedFrom classname or null
*
* @return array
*/
private function buildMethodPhpDoc($phpDocMethod, $inheritedFrom)
private function buildMethodPhpDoc(Abstraction $abs, $phpDocMethod, $inheritedFrom)
{
$className = $inheritedFrom
? $inheritedFrom
: $this->abs['className'];
: $abs['className'];
return $this->buildMethodValues(array(
'inheritedFrom' => $inheritedFrom,
'isStatic' => $phpDocMethod['static'],
'params' => $this->params->getParamsPhpDoc($this->abs, $phpDocMethod, $className),
'params' => $this->params->getParamsPhpDoc($abs, $phpDocMethod, $className),
'phpDoc' => array(
'desc' => null,
'summary' => $phpDocMethod['desc'],
),
'return' => array(
'desc' => null,
'type' => $this->helper->resolvePhpDocType($phpDocMethod['type'], $this->abs),
'type' => $this->helper->resolvePhpDocType($phpDocMethod['type'], $abs),
),
'visibility' => 'magic',
));
Expand All @@ -295,22 +306,25 @@ private function buildMethodPhpDoc($phpDocMethod, $inheritedFrom)
/**
* Get method info
*
* @param object|string $obj object (or classname) method belongs to
* @param Abstraction $abs Object Abstraction instance
* @param ReflectionMethod $refMethod ReflectionMethod instance
*
* @return array
*/
private function buildMethodRef($obj, ReflectionMethod $refMethod)
private function buildMethodRef(Abstraction $abs, ReflectionMethod $refMethod)
{
// getDeclaringClass() returns LAST-declared/overridden
$obj = $abs->getSubject();
// get_class() returns "raw" classname
// could be stdClass@anonymous/filepath.php:6$2e
// $abs['className'] is a "friendly" name ... just stdClass@anonymous
$className = \is_object($obj)
? \get_class($obj)
: $obj;
// getDeclaringClass() returns LAST-declared/overridden
$declaringClassName = $refMethod->getDeclaringClass()->getName();
$phpDoc = $this->helper->getPhpDoc($refMethod);
\ksort($phpDoc);
$info = $this->buildMethodValues(array(
'attributes' => $this->abs['cfgFlags'] & AbstractObject::METHOD_ATTRIBUTE_COLLECT
return $this->buildMethodValues(array(
'attributes' => $abs['cfgFlags'] & AbstractObject::METHOD_ATTRIBUTE_COLLECT
? $this->helper->getAttributes($refMethod)
: array(),
'inheritedFrom' => $declaringClassName !== $className
Expand All @@ -320,34 +334,32 @@ private function buildMethodRef($obj, ReflectionMethod $refMethod)
'isDeprecated' => $refMethod->isDeprecated() || isset($phpDoc['deprecated']),
'isFinal' => $refMethod->isFinal(),
'isStatic' => $refMethod->isStatic(),
'params' => $this->params->getParams($this->abs, $refMethod, $phpDoc),
'params' => $this->params->getParams($abs, $refMethod, $phpDoc),
'phpDoc' => $phpDoc,
'return' => $this->getReturn($refMethod, $phpDoc),
'return' => $this->getReturn($abs, $refMethod, $phpDoc),
'visibility' => $this->helper->getVisibility($refMethod),
));
unset($info['phpDoc']['param']);
unset($info['phpDoc']['return']);
return $info;
}

/**
* Get return type & desc
*
* @param Abstraction $abs Object Abstraction instance
* @param ReflectionMethod $refMethod ReflectionMethod
* @param array $phpDoc parsed phpDoc param info
*
* @return array
*/
private function getReturn(ReflectionMethod $refMethod, $phpDoc)
private function getReturn(Abstraction $abs, ReflectionMethod $refMethod, $phpDoc)
{
$return = array(
'desc' => null,
'type' => null,
);
if (!empty($phpDoc['return'])) {
$return = \array_merge($return, $phpDoc['return']);
$return['type'] = $this->helper->resolvePhpDocType($return['type'], $this->abs);
if (!($this->abs['cfgFlags'] & AbstractObject::PHPDOC_COLLECT)) {
$return['type'] = $this->helper->resolvePhpDocType($return['type'], $abs);
if (!($abs['cfgFlags'] & AbstractObject::PHPDOC_COLLECT)) {
$return['desc'] = null;
}
} elseif (PHP_VERSION_ID >= 70000) {
Expand All @@ -359,11 +371,12 @@ private function getReturn(ReflectionMethod $refMethod, $phpDoc)
/**
* Get object's __toString value if method is not deprecated
*
* @param Abstraction $abs Object Abstraction instance
*
* @return string|Abstraction|null
*/
private function toString()
private function toString(Abstraction $abs)
{
$abs = $this->abs;
// abs['methods']['__toString'] may not exist if via addMethodsMin
if (!empty($abs['methods']['__toString']['isDeprecated'])) {
return null;
Expand Down
Loading

0 comments on commit 195e730

Please sign in to comment.