src/Debug/PhpDoc.php
public static function parseTag($tag, $tagStr = '')
    {
        $parsed = array();
        $tagParsers = array(
            array(
                'tags' => array('param','property','property-read', 'property-write', 'var'),
                'parts' => array('type','name','desc'),
                'regex' => '/^'
                    .'(?:(?P<type>[^\$].*?)\s+)?'
                    .'(?:&?\$?(?P<name>\S+)\s+)?'
                    .'(?P<desc>.*)?'
                    .'$/s',
                'callable' => function ($tag, $parsed) {
                    if (\strpos($parsed['desc'], ' ') === false) {
                        if (!$parsed['type']) {
                            $parsed['type'] = $parsed['desc'];
                            $parsed['desc'] = null;
                        } elseif (!$parsed['name']) {
                            $parsed['name'] = \ltrim($parsed['desc'], '&$');
                            $parsed['desc'] = null;
                        }
                    }
                    return $parsed;
                },
            ),
            array(
                'tags' => array('method'),
                'parts' => array('static', 'type', 'name', 'param', 'desc'),
                'regex' => '/'
                    .'(?:(?P<static>static)\s+)?'
                    .'(?:(?P<type>.*?)\s+)?'
                    .'(?P<name>\S+)'
                    .'\((?P<param>((?>[^()]+)|(?R))*)\)'  // see http://php.net/manual/en/regexp.reference.recursive.php
                    .'(?:\s+(?P<desc>.*))?'
                    .'/s',
                'callable' => function ($tag, $parsed) {
                    $parsed['static'] = $parsed['static'] !== null;
                    $parsed['param'] = self::parseParams($parsed['param']);
                    return $parsed;
                },
            ),
            array(
                'tags' => array('return'),
                'parts' => array('type','desc'),
                'regex' => '/^(?P<type>.*?)'
                    .'(?:\s+(?P<desc>.*))?$/s',
            ),
            array(
                'tags' => array('link'),
                'parts' => array('uri', 'desc'),
                'regex' => '/^(?P<uri>\S+)'
                    .'(?:\s+(?P<desc>.*))?$/s',
            ),
            array(
                'tags' => array('see'),
                'parts' => array('uri', 'fqsen', 'desc'),
                'regex' => '/^(?:'
                    .'(?P<uri>https?:\/\/\S+)|(?P<fqsen>\S+)'
                    .')'
                    .'(?:\s+(?P<desc>.*))?$/s',
            ),
            array(
                // default
                'tags' => array(),
                'parts' => array('desc'),
                'regex' => '/^(?P<desc>.*?)$/s',
            ),
        );
        foreach ($tagParsers as $parser) {
            if (\in_array($tag, $parser['tags'])) {
                break;
            }
        }
        \preg_match($parser['regex'], $tagStr, $matches);
        foreach ($parser['parts'] as $part) {
            $parsed[$part] = isset($matches[$part]) && $matches[$part] !== ''
                ? \trim($matches[$part])
                : null;
        }
        if (isset($parser['callable'])) {
            $parsed = \call_user_func($parser['callable'], $tag, $parsed);
        }
        $parsed['desc'] = self::trimDesc($parsed['desc']);
        return $parsed;
    }
public static function parseTag($tag, $tagStr = '')
    {
        $parsed = array();
        $tagParsers = array(
            array(
                'tags' => array('param','property','property-read', 'property-write', 'var'),
                'parts' => array('type','name','desc'),
                'regex' => '/^'
                    .'(?:(?P<type>[^\$].*?)\s+)?'
                    .'(?:&?\$?(?P<name>\S+)\s+)?'
                    .'(?P<desc>.*)?'
                    .'$/s',
                'callable' => function ($tag, $parsed) {
                    if (\strpos($parsed['desc'], ' ') === false) {
                        if (!$parsed['type']) {
                            $parsed['type'] = $parsed['desc'];
                            $parsed['desc'] = null;
                        } elseif (!$parsed['name']) {
                            $parsed['name'] = \ltrim($parsed['desc'], '&$');
                            $parsed['desc'] = null;
                        }
                    }
                    return $parsed;
                },
            ),
            array(
                'tags' => array('method'),
                'parts' => array('static', 'type', 'name', 'param', 'desc'),
                'regex' => '/'
                    .'(?:(?P<static>static)\s+)?'
                    .'(?:(?P<type>.*?)\s+)?'
                    .'(?P<name>\S+)'
                    .'\((?P<param>((?>[^()]+)|(?R))*)\)'  // see http://php.net/manual/en/regexp.reference.recursive.php
                    .'(?:\s+(?P<desc>.*))?'
                    .'/s',
                'callable' => function ($tag, $parsed) {
                    $parsed['static'] = $parsed['static'] !== null;
                    $parsed['param'] = self::parseParams($parsed['param']);
                    return $parsed;
                },
            ),
            array(
                'tags' => array('return'),
                'parts' => array('type','desc'),
                'regex' => '/^(?P<type>.*?)'
                    .'(?:\s+(?P<desc>.*))?$/s',
            ),
            array(
                'tags' => array('link'),
                'parts' => array('uri', 'desc'),
                'regex' => '/^(?P<uri>\S+)'
                    .'(?:\s+(?P<desc>.*))?$/s',
            ),
            array(
                'tags' => array('see'),
                'parts' => array('uri', 'fqsen', 'desc'),
                'regex' => '/^(?:'
                    .'(?P<uri>https?:\/\/\S+)|(?P<fqsen>\S+)'
                    .')'
                    .'(?:\s+(?P<desc>.*))?$/s',
            ),
            array(
                // default
                'tags' => array(),
                'parts' => array('desc'),
                'regex' => '/^(?P<desc>.*?)$/s',
            ),
        );
        foreach ($tagParsers as $parser) {
            if (\in_array($tag, $parser['tags'])) {
                break;
            }
        }
        \preg_match($parser['regex'], $tagStr, $matches);
        foreach ($parser['parts'] as $part) {
            $parsed[$part] = isset($matches[$part]) && $matches[$part] !== ''
                ? \trim($matches[$part])
                : null;
        }
        if (isset($parser['callable'])) {
            $parsed = \call_user_func($parser['callable'], $tag, $parsed);
        }
        $parsed['desc'] = self::trimDesc($parsed['desc']);
        return $parsed;
    }
public static function parseTag ( $ tag , $ tagStr = '' ) { $ parsed = array ( ) ; $ tagParsers = array ( array ( 'tags' => array ( 'param' , 'property' , 'property-read' , 'property-write' , 'var' ) , 'parts' => array ( 'type' , 'name' , 'desc' ) , 'regex' => '/^' . '(?:(?P<type>[^\$].*?)\s+)?' . '(?:&?\$?(?P<name>\S+)\s+)?' . '(?P<desc>.*)?' . '$/s' , 'callable' => function ( $ tag , $ parsed ) { if ( \ strpos ( $ parsed [ 'desc' ] , ' ' ) === false ) { if ( ! $ parsed [ 'type' ] ) { $ parsed [ 'type' ] = $ parsed [ 'desc' ] ; $ parsed [ 'desc' ] = null ; } elseif ( ! $ parsed [ 'name' ] ) { $ parsed [ 'name' ] = \ ltrim ( $ parsed [ 'desc' ] , '&$' ) ; $ parsed [ 'desc' ] = null ; } } return $ parsed ; } , ) , array ( 'tags' => array ( 'method' ) , 'parts' => array ( 'static' , 'type' , 'name' , 'param' , 'desc' ) , 'regex' => '/' . '(?:(?P<static>static)\s+)?' . '(?:(?P<type>.*?)\s+)?' . '(?P<name>\S+)' . '\((?P<param>((?>[^()]+)|(?R))*)\)' // see http://php.net/manual/en/regexp.reference.recursive.php . '(?:\s+(?P<desc>.*))?' . '/s' , 'callable' => function ( $ tag , $ parsed ) { $ parsed [ 'static' ] = $ parsed [ 'static' ] !== null ; $ parsed [ 'param' ] = self :: parseParams ( $ parsed [ 'param' ] ) ; return $ parsed ; } , ) , array ( 'tags' => array ( 'return' ) , 'parts' => array ( 'type' , 'desc' ) , 'regex' => '/^(?P<type>.*?)' . '(?:\s+(?P<desc>.*))?$/s' , ) , array ( 'tags' => array ( 'link' ) , 'parts' => array ( 'uri' , 'desc' ) , 'regex' => '/^(?P<uri>\S+)' . '(?:\s+(?P<desc>.*))?$/s' , ) , array ( 'tags' => array ( 'see' ) , 'parts' => array ( 'uri' , 'fqsen' , 'desc' ) , 'regex' => '/^(?:' . '(?P<uri>https?:\/\/\S+)|(?P<fqsen>\S+)' . ')' . '(?:\s+(?P<desc>.*))?$/s' , ) , array ( // default 'tags' => array ( ) , 'parts' => array ( 'desc' ) , 'regex' => '/^(?P<desc>.*?)$/s' , ) , ) ; foreach ( $ tagParsers as $ parser ) { if ( \ in_array ( $ tag , $ parser [ 'tags' ] ) ) { break ; } } \ preg_match ( $ parser [ 'regex' ] , $ tagStr , $ matches ) ; foreach ( $ parser [ 'parts' ] as $ part ) { $ parsed [ $ part ] = isset ( $ matches [ $ part ] ) && $ matches [ $ part ] !== '' ? \ trim ( $ matches [ $ part ] ) : null ; } if ( isset ( $ parser [ 'callable' ] ) ) { $ parsed = \ call_user_func ( $ parser [ 'callable' ] , $ tag , $ parsed ) ; } $ parsed [ 'desc' ] = self :: trimDesc ( $ parsed [ 'desc' ] ) ; return $ parsed ; }
Parse phpDoc tag

Notes:
\@method tag:
optional "static" keyword may preceed type & name
'static' returned as a boolean value
parameters:  defaultValue key only returned if defined.
defaultValue is not parsed

@param string $tag    tag type
@param string $tagStr tag values (ie "[Type] [name] [<description>]")

@return array
Parse phpDoc tag