Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.16% covered (success)
95.16%
59 / 62
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
ClassReflection
95.16% covered (success)
95.16%
59 / 62
0.00% covered (danger)
0.00%
0 / 1
31
0.00% covered (danger)
0.00%
0 / 1
 parse
95.16% covered (success)
95.16%
59 / 62
0.00% covered (danger)
0.00%
0 / 1
31
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Code\Reflection;
15
16use Pop\Code\Generator;
17use ReflectionException;
18
19/**
20 * Class reflection code class
21 *
22 * @category   Pop
23 * @package    Pop\Code
24 * @author     Nick Sagona, III <dev@nolainteractive.com>
25 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
26 * @license    http://www.popphp.org/license     New BSD License
27 * @version    5.0.0
28 */
29class ClassReflection extends AbstractReflection
30{
31
32    /**
33     * Method to parse a class
34     *
35     * @param  mixed   $code
36     * @param  ?string $name
37     * @throws Exception|ReflectionException
38     * @return Generator\ClassGenerator
39     */
40    public static function parse(mixed $code, ?string $name = null): Generator\ClassGenerator
41    {
42        $reflection     = new \ReflectionClass($code);
43        $reflectionName = $reflection->getShortName();
44        $reflectionFile = $reflection->getFileName();
45        $fileContents   = null;
46
47        if (!empty($reflectionFile) && file_exists($reflectionFile)) {
48            $fileContents = file_get_contents($reflectionFile);
49        }
50
51        if (($name === null) && !empty($reflectionName)) {
52            $name = $reflectionName;
53        }
54
55        if (($reflection->isInterface()) || ($reflection->isTrait())) {
56            throw new Exception('Error: The code must be a class, not an interface or trait.');
57        }
58
59        $class = new Generator\ClassGenerator($name);
60
61        // Detect and set namespace
62        if (($reflection->inNamespace()) && ($fileContents !== null)) {
63            $class->setNamespace(NamespaceReflection::parse($fileContents, $reflection->getNamespaceName()));
64        }
65
66        // Detect and set the class doc block
67        $classDocBlock = $reflection->getDocComment();
68        if (!empty($classDocBlock) && (str_contains($classDocBlock, '/*'))) {
69            $class->setDocblock(DocblockReflection::parse($classDocBlock));
70        }
71
72        if ($reflection->isAbstract()) {
73            $class->setAsAbstract(true);
74        } else if ($reflection->isFinal()) {
75            $class->setAsFinal(true);
76        }
77
78        // Detect parent class
79        $parent = $reflection->getParentClass();
80        if ($parent !== false) {
81            if ($parent->inNamespace()) {
82                if (!$class->hasNamespace()) {
83                    $class->setNamespace(new Generator\NamespaceGenerator());
84                }
85                $class->getNamespace()->addUse($parent->getNamespaceName() . '\\' . $parent->getShortName());
86            }
87            $class->setParent($parent->getShortName());
88        }
89
90        // Detect implemented interfaces
91        $interfaces = $reflection->getInterfaces();
92        if ($interfaces !== false) {
93            $interfacesAry = [];
94            foreach ($interfaces as $interface) {
95                if ($interface->inNamespace()) {
96                    if (!$class->hasNamespace()) {
97                        $class->setNamespace(new Generator\NamespaceGenerator());
98                    }
99                    $class->getNamespace()->addUse($interface->getNamespaceName() . '\\' . $interface->getShortName());
100                }
101                $interfacesAry[] = $interface->getShortName();
102            }
103            $class->addInterfaces($interfacesAry);
104        }
105
106        // Detect used traits
107        if ($fileContents !== null) {
108            $uses = [];
109            preg_match_all('/[ ]+use(.*);$/m', $fileContents, $uses);
110
111            if (isset($uses[1])) {
112                foreach ($uses[1] as $u) {
113                    $useAry = array_map('trim', explode(',', trim($u)));
114                    foreach ($useAry as $useValue) {
115                        if (strpos($useValue, ' as ') !== false) {
116                            [$use, $as] = explode(' as ', $useValue);
117                        } else {
118                            $use = $useValue;
119                            $as  = null;
120                        }
121                        $class->addUse($use, $as);
122                    }
123                }
124            }
125        }
126
127        // Detect constants
128        $constants = $reflection->getConstants();
129        if (count($constants) > 0) {
130            foreach ($constants as $key => $value) {
131                $class->addConstant(new Generator\ConstantGenerator($key, gettype($value), $value));
132            }
133        }
134
135        // Detect properties
136        $properties = $reflection->getDefaultProperties();
137        if (count($properties) > 0) {
138            foreach ($properties as $name => $value) {
139                $class->addProperty(PropertyReflection::parse($reflection->getProperty($name), $name, $value));
140            }
141        }
142
143        // Detect methods
144        $methods = $reflection->getMethods();
145        if (count($methods) > 0) {
146            foreach ($methods as $method) {
147                $class->addMethod(MethodReflection::parse($method, $method->name));
148            }
149        }
150
151        return $class;
152    }
153
154}