Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.53% covered (success)
98.53%
67 / 68
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
MethodReflection
98.53% covered (success)
98.53%
67 / 68
0.00% covered (danger)
0.00%
0 / 1
35
0.00% covered (danger)
0.00%
0 / 1
 parse
98.53% covered (success)
98.53%
67 / 68
0.00% covered (danger)
0.00%
0 / 1
35
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;
17
18/**
19 * Method reflection code class
20 *
21 * @category   Pop
22 * @package    Pop\Code
23 * @author     Nick Sagona, III <dev@nolainteractive.com>
24 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
25 * @license    http://www.popphp.org/license     New BSD License
26 * @version    5.0.0
27 */
28class MethodReflection extends AbstractReflection
29{
30
31    /**
32     * Method to parse a method
33     *
34     * @param  mixed   $code
35     * @param  ?string $name
36     * @return Generator\MethodGenerator
37     */
38    public static function parse(mixed $code, ?string $name = null): Generator\MethodGenerator
39    {
40        if ($code->isProtected()) {
41            $visibility = 'protected';
42        } else if ($code->isPrivate()) {
43            $visibility = 'private';
44        } else {
45            $visibility = 'public';
46        }
47
48        $docblock = null;
49        $doc      = $code->getDocComment();
50        if (($doc !== null) && (str_contains($doc, '/*'))) {
51            $docblock = DocblockReflection::parse($doc);
52            $docblock->setIndent(4);
53        }
54
55        $method = new Generator\MethodGenerator($code->getName(), $visibility, $code->isStatic());
56        if ($docblock !== null) {
57            $method->setDocblock($docblock);
58        }
59
60        if ($code->isAbstract()) {
61            $method->setAsAbstract(true);
62        } else if ($code->isFinal()) {
63            $method->setAsFinal(true);
64        }
65
66        $reflectionParams = $code->getParameters();
67
68        foreach ($reflectionParams as $key => $reflectionParam) {
69            $paramName  = $reflectionParam->getName();
70            $paramType  = $reflectionParam->getType();
71            $paramType  = (!empty($paramType) && ($paramType instanceof \ReflectionType) &&
72                method_exists($paramType, 'getName')) ? $paramType->getName() : null;
73
74            try {
75                $paramValue = $reflectionParam->getDefaultValue();
76            } catch (\ReflectionException $e) {
77                $paramValue = null;
78            }
79
80            $method->addArgument($paramName, $paramValue, $paramType);
81        }
82
83        // Parse the body if available
84        $file = $code->getFileName();
85
86        if (!empty($file) && file_exists($file)) {
87            $lines     = file($file);
88            $startLine = $code->getStartLine() - 1;
89            $endLine   = $code->getEndLine() - 1;
90            $length    = $endLine - $startLine;
91            $body      = null;
92
93            if (($length > 0) && isset($lines[$startLine]) && isset($lines[$endLine])) {
94                $lines = array_slice($lines, ($startLine + 1), $length);
95
96                if (preg_match('/[ ]+\}/', $lines[(count($lines) - 1)])) {
97                    unset($lines[(count($lines) - 1)]);
98                }
99                if (isset($lines[0]) && preg_match('/[ ]+\{/', $lines[0])) {
100                    unset($lines[0]);
101                }
102
103                $lines = array_values($lines);
104
105                if (isset($lines[0]) && (str_starts_with($lines[0], ' '))) {
106                    $spaces = strlen($lines[0]) - strlen(ltrim($lines[0]));
107                    if ($spaces > 0) {
108                        $lines = array_map(function($value) use ($spaces) {
109                            if (substr($value, 0, $spaces) == str_repeat(' ', $spaces)) {
110                                $value = substr($value, $spaces);
111                            }
112                            return $value;
113                        }, $lines);
114                    }
115                }
116
117                $body = implode('', $lines);
118            }
119
120            if (!empty($body)) {
121                $method->setBody($body);
122            }
123        }
124
125        // Get return type(s)
126        if ($code->hasReturnType()) {
127            $namedTypes  = [];
128            $returnTypes = $code->getReturnType();
129            if ($returnTypes instanceof \ReflectionUnionType) {
130                $types = $returnTypes->getTypes();
131                foreach ($types as $type) {
132                    $namedTypes[] = $type->getName();
133                }
134                if (($returnTypes->allowsNull()) && !in_array('null', $namedTypes)) {
135                    $namedTypes[] = 'null';
136                }
137            } else if ($returnTypes instanceof \ReflectionNamedType) {
138                $namedTypes[] = $returnTypes->getName();
139                if (($returnTypes->allowsNull()) && !in_array('null', $namedTypes)) {
140                    $namedTypes[] = 'null';
141                }
142            }
143            if (!empty($namedTypes)) {
144                $method->addReturnTypes($namedTypes);
145            }
146        }
147
148        return $method;
149    }
150
151}