src/CapableServer.php
protected static function extractTypes($doc)
    {
        $doc    = trim(substr($doc, 3, -2), " \t\r\n*");
        $doc    = str_replace(array("\r\n", "\r"), "\n", $doc);
        $lines  = explode("\n", $doc . "\n");

        $tag    = null;
        $tags   = array(
            'params'    => array(),
            'retval'    => 'null',
        );
        $buffer = '';

        foreach ($lines as $line) {
            $line = trim($line, " \r\n\t*");

            if ($tag !== null && $line === '') {
                switch ($tag) {
                    case 'param':
                        $type = (string) substr($buffer, 0, strcspn($buffer, " \r\n\t"));
                        $buffer = ltrim(substr($buffer, strcspn($buffer, " \r\n\t")));
                        if (strncmp($buffer, '$', 1)) {
                            break;
                        }

                        $name = (string) substr($buffer, 1, strcspn($buffer, " \r\n\t") - 1);
                        $tags['params'][$name] = $type;
                        break;

                    case 'retval':
                        $type = (string) substr($buffer, 0, strcspn($buffer, " \r\n\t"));
                        $tags['retval'] = $type;
                        break;
                }

                $tag    = null;
                $buffer = '';
                continue;
            }

            if ($tag === null) {
                // \command or @command.
                if (!strncmp($line, '\\', 1) || !strncmp($line, '@', 1)) {
                    $tag    = (string) substr($line, 1, strcspn($line, " \r\n\t") - 1);
                    $buffer = ltrim(substr($line, strcspn($line, " \r\n\t")));
                }
            } else {
                // Continuation of previous paragraph.
                $buffer .= "\n$line";
            }
        }
        return $tags;
    }
protected static function extractTypes($doc)
    {
        $doc    = trim(substr($doc, 3, -2), " \t\r\n*");
        $doc    = str_replace(array("\r\n", "\r"), "\n", $doc);
        $lines  = explode("\n", $doc . "\n");

        $tag    = null;
        $tags   = array(
            'params'    => array(),
            'retval'    => 'null',
        );
        $buffer = '';

        foreach ($lines as $line) {
            $line = trim($line, " \r\n\t*");

            if ($tag !== null && $line === '') {
                switch ($tag) {
                    case 'param':
                        $type = (string) substr($buffer, 0, strcspn($buffer, " \r\n\t"));
                        $buffer = ltrim(substr($buffer, strcspn($buffer, " \r\n\t")));
                        if (strncmp($buffer, '$', 1)) {
                            break;
                        }

                        $name = (string) substr($buffer, 1, strcspn($buffer, " \r\n\t") - 1);
                        $tags['params'][$name] = $type;
                        break;

                    case 'retval':
                        $type = (string) substr($buffer, 0, strcspn($buffer, " \r\n\t"));
                        $tags['retval'] = $type;
                        break;
                }

                $tag    = null;
                $buffer = '';
                continue;
            }

            if ($tag === null) {
                // \command or @command.
                if (!strncmp($line, '\\', 1) || !strncmp($line, '@', 1)) {
                    $tag    = (string) substr($line, 1, strcspn($line, " \r\n\t") - 1);
                    $buffer = ltrim(substr($line, strcspn($line, " \r\n\t")));
                }
            } else {
                // Continuation of previous paragraph.
                $buffer .= "\n$line";
            }
        }
        return $tags;
    }
Extract parameter and return type information
from a documentation comment.

\param string $doc
Documentation comment the types
will be extracted from.

\retval array
Array with type information.
The "retval" key contains information about the return type,
while the array in the "params" key contains information
about each parameter's type (indexed by its name).