public static function parse($string, $tags = '*'): array
    {
        //in case we don't have any tag to detect or an empty doc comment, we skip this method
        if (empty($tags) || empty($string)) {
            return [];
        }
   
        //check what is the type of $tags (array|string|wildcard)
        if (is_array($tags)) {
            $tags = '('.implode('|', $tags).')';
        } elseif ($tags === '*') {
            $tags = '[a-zA-Z0-9]';
        } else {
            $tags = '('.$tags.')';
        }
        
        //find @[tag] [params...]
        $regex = '#\* @(?P<tag>'.$tags.'+)\s+((?P<data>[\s"a-zA-Z0-9\-$\\._/-^]+)){1,}#si';
        preg_match_all($regex, $string, $matches, PREG_SET_ORDER);
        
        $final = [];
        
        if (isset($matches)) {
            $i = 0;
            foreach ($matches as $v) {
                $final[$i] = array('tag' => $v['tag'], 'data' => []);

                //detect here if we got a param with quote or not
                //since space is the separator between params, if a param need space(s),
                //it must be surrounded by " to be detected as 1 param
                $regex = '#(("(?<param>([^"]{1,}))")|(?<param2>([^"\s]{1,})))#i';
                preg_match_all($regex, trim($v['data']), $matches_params, PREG_SET_ORDER);

                if (!empty($matches_params)) {
                    foreach ($matches_params as $v) {
                        if (!empty($v['param']) && !isset($v['param2'])) {
                            $final[$i]['data'][] = $v['param'];
                        } elseif (isset($v['param2']) && !empty($v['param2'])) {
                            $final[$i]['data'][] = $v['param2'];
                        }
                    }
                }
                
                ++$i;
            }
        }
        
        return $final;
    }