Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
51 / 51
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
DocblockReflection
100.00% covered (success)
100.00%
51 / 51
100.00% covered (success)
100.00%
1 / 1
15
100.00% covered (success)
100.00%
1 / 1
 parse
100.00% covered (success)
100.00%
51 / 51
100.00% covered (success)
100.00%
1 / 1
15
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\DocblockGenerator;
17
18/**
19 * Docblock 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 DocblockReflection extends AbstractReflection
29{
30
31    /**
32     * Method to parse a docblock
33     *
34     * @param  mixed $code
35     * @param  ?int  $forceIndent
36     * @throws Exception
37     * @return DocblockGenerator
38     */
39    public static function parse(mixed $code, ?int $forceIndent = null): DocblockGenerator
40    {
41        if ((!str_contains($code, '/*')) || (!str_contains($code, '*/'))) {
42            throw new Exception('The docblock is not in the correct format.');
43        }
44
45        $desc          = null;
46        $formattedDesc = null;
47        $indent        = null;
48        $tags          = null;
49
50        // Parse the description, if any
51        if (str_contains($code, '@')) {
52            $desc    = substr($code, 0, strpos($code, '@'));
53            $desc    = str_replace('/*', '', $desc);
54            $desc    = str_replace('*/', '', $desc);
55            $desc    = str_replace(PHP_EOL . ' * ', ' ', $desc);
56            $desc    = trim(str_replace('*', '', $desc));
57            $descAry = explode("\n", $desc);
58
59            $formattedDesc = null;
60            foreach ($descAry as $line) {
61                $formattedDesc .= ' ' . trim($line);
62            }
63
64            $formattedDesc = trim($formattedDesc);
65        }
66
67        // Get the indentation, if any, and create docblock object
68        $indent      = (empty($forceIndent)) ? strlen(substr($code, 0, strpos($code, '/'))) : $forceIndent;
69        $docblock = new DocblockGenerator($formattedDesc, $indent);
70
71        // Get the tags, if any
72        if (str_contains($code, '@')) {
73            $tags    = substr($code, strpos($code, '@'));
74            $tags    = substr($tags, 0, strpos($tags, '*/'));
75            $tags    = str_replace('*', '', $tags);
76            $tagsAry = explode("\n", $tags);
77
78            foreach ($tagsAry as $key => $value) {
79                $value = trim(str_replace('@', '', $value));
80                // Param tags
81                if (stripos($value, 'param') !== false) {
82                    $paramTag  = trim(str_replace('param', '', $value));
83                    $paramType = trim(substr($paramTag, 0, strpos($paramTag, ' ')));
84                    $varName   = null;
85                    $paramDesc = null;
86                    if (str_contains($paramTag, ' ')) {
87                        $varName = trim(substr($paramTag, strpos($paramTag, ' ')));
88                        if (str_contains($varName, ' ')) {
89                            $paramDesc = trim(substr($varName, strpos($varName, ' ')));
90                        }
91                    } else {
92                        $paramType = $paramTag;
93                    }
94                    $docblock->addParam($paramType, $varName, $paramDesc);
95                // Else, return tags
96                } else if (stripos($value, 'return') !== false) {
97                    $returnTag = trim(str_replace('return', '', $value));
98                    if (str_contains($returnTag, ' ')) {
99                        $returnType = substr($returnTag, 0, strpos($returnTag, ' '));
100                        $returnDesc = trim(str_replace($returnType, '', $returnTag));
101                    } else {
102                        $returnType = $returnTag;
103                        $returnDesc = null;
104                    }
105                    $docblock->setReturn($returnType, $returnDesc);
106                // Else, all other tags
107                } else {
108                    $tagName = trim(substr($value, 0, strpos($value, ' ')));
109                    $tagDesc = trim(str_replace($tagName, '', $value));
110                    if (!empty($tagName) && !empty($tagDesc)) {
111                        $docblock->addTag($tagName, $tagDesc);
112                    } else {
113                        unset($tagsAry[$key]);
114                    }
115                }
116            }
117        }
118
119        return $docblock;
120    }
121
122}