Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
70.00% |
7 / 10 |
CRAP | |
88.00% |
132 / 150 |
Reflection | |
0.00% |
0 / 1 |
|
70.00% |
7 / 10 |
69.86 | |
88.00% |
132 / 150 |
__construct | |
100.00% |
1 / 1 |
2 | |
100.00% |
7 / 7 |
|||
getClassString | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getObjectInstance | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
isClassString | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
isObjectInstance | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
generator | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
buildGenerator | |
100.00% |
1 / 1 |
14 | |
100.00% |
29 / 29 |
|||
getClassNamespace | |
0.00% |
0 / 1 |
7.07 | |
88.89% |
16 / 18 |
|||
getClassProperties | |
0.00% |
0 / 1 |
10.15 | |
88.46% |
23 / 26 |
|||
getClassMethods | |
0.00% |
0 / 1 |
30.00 | |
80.00% |
52 / 65 |
<?php | |
/** | |
* Pop PHP Framework (http://www.popphp.org/) | |
* | |
* @link https://github.com/popphp/popphp-framework | |
* @author Nick Sagona, III <dev@nolainteractive.com> | |
* @copyright Copyright (c) 2009-2019 NOLA Interactive, LLC. (http://www.nolainteractive.com) | |
* @license http://www.popphp.org/license New BSD License | |
*/ | |
/** | |
* @namespace | |
*/ | |
namespace Pop\Code; | |
use Pop\Code\Generator; | |
/** | |
* Reflection code class | |
* | |
* @category Pop | |
* @package Pop\Code | |
* @author Nick Sagona, III <dev@nolainteractive.com> | |
* @copyright Copyright (c) 2009-2019 NOLA Interactive, LLC. (http://www.nolainteractive.com) | |
* @license http://www.popphp.org/license New BSD License | |
* @version 3.1.1 | |
*/ | |
class Reflection extends \ReflectionClass | |
{ | |
/** | |
* Class string to reflect | |
* @var string | |
*/ | |
protected $classString = null; | |
/** | |
* Object instance to reflect | |
* @var Object | |
*/ | |
protected $objectInstance = null; | |
/** | |
* Code generator object | |
* @var Generator | |
*/ | |
protected $generator = null; | |
/** | |
* Constructor | |
* | |
* Instantiate the code reflection object | |
* | |
* @param mixed $class | |
*/ | |
public function __construct($class) | |
{ | |
if (is_string($class)) { | |
$this->classString = $class; | |
} else { | |
$this->objectInstance = $class; | |
$this->classString = get_class($class); | |
} | |
parent::__construct($class); | |
$this->buildGenerator(); | |
} | |
/** | |
* Get the class string | |
* | |
* @return string | |
*/ | |
public function getClassString() | |
{ | |
return $this->classString; | |
} | |
/** | |
* Get the object instance | |
* | |
* @return string | |
*/ | |
public function getObjectInstance() | |
{ | |
return $this->objectInstance; | |
} | |
/** | |
* Determine if the argument passed was a class string | |
* | |
* @return boolean | |
*/ | |
public function isClassString() | |
{ | |
return (null === $this->objectInstance); | |
} | |
/** | |
* Determine if the argument passed was an object instance | |
* | |
* @return boolean | |
*/ | |
public function isObjectInstance() | |
{ | |
return (null !== $this->objectInstance); | |
} | |
/** | |
* Get the generator | |
* | |
* @return Generator | |
*/ | |
public function generator() | |
{ | |
return $this->generator; | |
} | |
/** | |
* Build the code generator based the reflection class | |
* | |
* @return void | |
*/ | |
protected function buildGenerator() | |
{ | |
// Create generator object | |
$type = ($this->isInterface()) ? Generator::CREATE_INTERFACE : Generator::CREATE_CLASS; | |
$this->generator = new Generator($this->getShortName() . '.php', $type); | |
// Get the namespace | |
$this->getClassNamespace(); | |
// Detect and set the class doc block | |
$classDocBlock = $this->getDocComment(); | |
if (!empty($classDocBlock) && (strpos($classDocBlock, '/*') !== false)) { | |
$this->generator->code()->setDocblock(Generator\DocblockGenerator::parse($classDocBlock)); | |
} | |
// Detect and set if the class is abstract | |
if (!$this->isInterface() && $this->isAbstract()) { | |
$this->generator->code()->setAbstract(true); | |
} | |
// Detect and set if the class is a child class | |
$parent = $this->getParentClass(); | |
if ($parent !== false) { | |
if ($parent->inNamespace()) { | |
$this->generator->getNamespace()->setUse($parent->getNamespaceName() . '\\' . $parent->getShortName()); | |
} | |
$this->generator->code()->setParent($parent->getShortName()); | |
} | |
// Detect and set if the class implements any interfaces | |
if (!$this->isInterface()) { | |
$interfaces = $this->getInterfaces(); | |
if ($interfaces !== false) { | |
$interfacesAry = []; | |
foreach ($interfaces as $interface) { | |
if ($interface->inNamespace()) { | |
$this->generator->getNamespace()->setUse($interface->getNamespaceName() . '\\' . $interface->getShortName()); | |
} | |
$interfacesAry[] = $interface->getShortName(); | |
} | |
$this->generator->code()->setInterface(implode(', ', $interfacesAry)); | |
} | |
} | |
// Detect and set constants | |
$constants = $this->getConstants(); | |
if (count($constants) > 0) { | |
foreach ($constants as $key => $value) { | |
$this->generator->code()->addProperty(new Generator\PropertyGenerator($key, gettype($value), $value, 'const')); | |
} | |
} | |
// Get properties | |
$this->getClassProperties(); | |
// Get Methods | |
$this->getClassMethods(); | |
} | |
/** | |
* Get the namespace and uses, if any | |
* | |
* @return void | |
*/ | |
protected function getClassNamespace() | |
{ | |
$fileContents = (file_exists($this->getFilename())) ? file_get_contents($this->getFilename()) : null; | |
// Detect and set namespace | |
if ($this->inNamespace()) { | |
$this->generator->setNamespace(new Generator\NamespaceGenerator($this->getNamespaceName())); | |
if (null !== $fileContents) { | |
$matches = []; | |
preg_match('/^use(.*)/m', $fileContents, $matches, PREG_OFFSET_CAPTURE); | |
if (isset($matches[0][0])) { | |
$uses = substr($fileContents, $matches[0][1] + 4); | |
$uses = substr($uses, 0, strpos($uses, ';')); | |
$usesAry = explode(',', $uses); | |
foreach ($usesAry as $use) { | |
$use = trim($use); | |
$as = null; | |
if (stripos($use, 'as') !== false) { | |
$as = trim(substr($use, (strpos($use, 'as') + 2))); | |
$use = trim(substr($use, 0, strpos($use, 'as'))); | |
} | |
$this->generator->getNamespace()->setUse($use, $as); | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Get properties | |
* | |
* @return void | |
*/ | |
protected function getClassProperties() | |
{ | |
// Detect and set properties | |
$properties = $this->getDefaultProperties(); | |
if (count($properties) > 0) { | |
foreach ($properties as $name => $value) { | |
$property = $this->getProperty($name); | |
$visibility = 'public'; | |
if ($property->isPublic()) { | |
$visibility = 'public'; | |
} else if ($property->isProtected()) { | |
$visibility = 'protected'; | |
} else if ($property->isPrivate()) { | |
$visibility = 'private'; | |
} | |
$doc = $property->getDocComment(); | |
if ((null !== $doc) && (strpos($doc, '/*') !== false)) { | |
$docblock = Generator\DocblockGenerator::parse($doc); | |
$desc = $docblock->getDesc(); | |
$type = $docblock->getTag('var'); | |
} else { | |
$type = strtolower(gettype($value)); | |
$desc = null; | |
} | |
if (is_array($value)) { | |
$formattedValue = (count($value) == 0) ? null : $value; | |
} else { | |
$formattedValue = $value; | |
} | |
$prop = new Generator\PropertyGenerator($property->getName(), $type, $formattedValue, $visibility); | |
$prop->setStatic($property->isStatic()); | |
$prop->setDesc($desc); | |
$this->generator->code()->addProperty($prop); | |
} | |
} | |
} | |
/** | |
* Get methods | |
* | |
* @return void | |
*/ | |
protected function getClassMethods() | |
{ | |
// Detect and set methods | |
$methods = $this->getMethods(); | |
if (count($methods) > 0) { | |
foreach ($methods as $value) { | |
$methodExport = \ReflectionMethod::export($value->class, $value->name, true); | |
// Get the method docblock | |
if ((strpos($methodExport, '/*') !== false) && (strpos($methodExport, '*/') !== false)) { | |
$docBlock = substr($methodExport, strpos($methodExport, '/*')); | |
$docBlock = substr($docBlock, 0, (strpos($methodExport, '*/') + 2)); | |
} else { | |
$docBlock = null; | |
} | |
$method = $this->getMethod($value->name); | |
$visibility = 'public'; | |
if ($method->isPublic()) { | |
$visibility = 'public'; | |
} else if ($method->isProtected()) { | |
$visibility = 'protected'; | |
} else if ($method->isPrivate()) { | |
$visibility = 'private'; | |
} | |
$mthd = new Generator\MethodGenerator($value->name, $visibility, $method->isStatic()); | |
if ((null !== $docBlock) && (strpos($docBlock, '/*') !== false)) { | |
$mthd->setDocblock(Generator\DocblockGenerator::parse($docBlock, $mthd->getIndent())); | |
} | |
$mthd->setFinal($method->isFinal()) | |
->setAbstract($method->isAbstract()); | |
// Get the method parameters | |
if (stripos($methodExport, 'Parameter') !== false) { | |
$matches = []; | |
preg_match_all('/Parameter \#(.*)\]/m', $methodExport, $matches); | |
if (isset($matches[0][0])) { | |
foreach ($matches[0] as $param) { | |
$name = null; | |
$value = null; | |
$type = null; | |
// Get name | |
$name = substr($param, strpos($param, '$')); | |
$name = trim(substr($name, 0, strpos($name, ' '))); | |
// Get value | |
if (strpos($param, '=') !== false) { | |
$value = trim(substr($param, (strpos($param, '=') + 1))); | |
$value = trim(substr($value, 0, strpos($value, ' '))); | |
$value = str_replace('NULL', 'null', $value); | |
} | |
// Get type | |
$type = substr($param, (strpos($param, '>') + 1)); | |
$type = trim(substr($type, 0, strpos($type, '$'))); | |
if ($type == '') { | |
$type = null; | |
} | |
$mthd->addArgument($name, $value, $type); | |
} | |
} | |
} | |
// Get method body | |
if ((strpos($methodExport, '@@') !== false) && (file_exists($this->getFilename()))) { | |
$lineNums = substr($methodExport, (strpos($methodExport, '@@ ') + 3)); | |
$start = trim(substr($lineNums, strpos($lineNums, ' '))); | |
$end = substr($start, (strpos($start, ' - ') + 3)); | |
$start = substr($start, 0, strpos($start, ' ')); | |
$end = (int)$end; | |
if (is_numeric($start) && is_numeric($end)) { | |
$classLines = file($this->getFilename()); | |
$body = null; | |
$start = $start + 1; | |
$end = $end - 1; | |
for ($i = $start; $i < $end; $i++) { | |
if (isset($classLines[$i])) { | |
if (substr($classLines[$i], 0, 8) == ' ') { | |
$body .= substr($classLines[$i], 8); | |
} else if (substr($classLines[$i], 0, 4) == ' ') { | |
$body .= substr($classLines[$i], 4); | |
} else if (substr($classLines[$i], 0, 2) == "\t\t") { | |
$body .= substr($classLines[$i], 2); | |
} else if (substr($classLines[$i], 0, 1) == "\t") { | |
$body .= substr($classLines[$i], 1); | |
} else { | |
$body .= $classLines[$i]; | |
} | |
} | |
} | |
$mthd->setBody(rtrim($body), false); | |
} | |
} | |
$this->generator->code()->addMethod($mthd); | |
} | |
} | |
} | |
} |