Reflection over PHPDoc with PHP

I want to parse PHPDoc code. Let me explain a little bit what I want to do. Imagine a dummy function documented with PHPDoc:

class Foo
     * @param String $param1
     * @param String $param2
     * @return String
    public function dummy($param1, $param2)
        return "Hello World";

PHP has a great reflection API, but as at least in the current PHP version (as far as I know) we only can get the PHPDoc as a string, without parse it. I need to get the parameters and the type of them with reflection. Parameters are the easy part:

$class = new ReflectionClass($obj);
$reflect = $class->getMethod($function);
foreach ($reflect->getParameters() as $i => $param) {

But the type is different. PHP is a loosely/weak typed, dynamic language, because of that we need to parse the PHPDoc string to get the “real” type of the variables. I put “real” quoted because if we set a variable as a String within PHPDoc, we can use an Integer at runtime. We can cast variables but only with complex types (classes), and not with primary types as String or Integer. I’ve read it will be available on PHP’s next releases, but now we need to use exotic tricks (as the trick I will show now).

I’m not a master in regular expressions (in fact I hate them), so it looks like a hard work for me, but I realized that Zend Framework does something similar when it builds a XMLRPC server. I don’t use ZF in this project, and I don’t want to include the whole library only for parsing the PHPDoc. But there’s a great thing. ZF is an open source library, really well coded and documented. Because of that I dive into the ZF code, looking for the functionality that I need and adapt it.

function processPHPDoc(ReflectionMethod $reflect)
    $phpDoc = array('params' => array(), 'return' => null);
    $docComment = $reflect->getDocComment();
    if (trim($docComment) == '') {
        return null;
    $docComment = preg_replace('#[ \t]*(?:\/\*\*|\*\/|\*)?[ ]{0,1}(.*)?#', '$1', $docComment);
    $docComment = ltrim($docComment, "\r\n");
    $parsedDocComment = $docComment;
    $lineNumber = $firstBlandLineEncountered = 0;
    while (($newlinePos = strpos($parsedDocComment, "\n")) !== false) {
        $line = substr($parsedDocComment, 0, $newlinePos);

        $matches = array();
        if ((strpos($line, '@') === 0) && (preg_match('#^(@\w+.*?)(\n)(?:@|\r?\n|$)#s', $parsedDocComment, $matches))) {
            $tagDocblockLine = $matches[1];
            $matches2 = array();

            if (!preg_match('#^@(\w+)(\s|$)#', $tagDocblockLine, $matches2)) {
            $matches3 = array();
            if (!preg_match('#^@(\w+)\s+([\w|\\\]+)(?:\s+(\$\S+))?(?:\s+(.*))?#s', $tagDocblockLine, $matches3)) {
            if ($matches3[1] != 'param') {
                if (strtolower($matches3[1]) == 'return') {
                    $phpDoc['return'] = array('type' => $matches3[2]);
            } else {
                $phpDoc['params'][] = array('name' => $matches3[3], 'type' => $matches3[2]);

            $parsedDocComment = str_replace($matches[1] . $matches[2], '', $parsedDocComment);
    return $phpDoc;

Our processPHPDoc function takes as argument $reflect (ReflectionMethod) and returns an array

    [params] => Array
            [0] => Array
                    [name] => $param1
                    [type] => String

            [1] => Array
                    [name] => $param2
                    [type] => String

    [return] => Array
            [type] => String

And that was exactly what I needed. Open Source is great.

About Gonzalo Ayuso

Web Architect. PHP, Python, Node, Angular, ionic, PostgreSQL, Linux, ... Always learning.

Posted on April 4, 2011, in php, tips and tagged , , . Bookmark the permalink. 4 Comments.

  1. Regular expressions are the best thing that ever happened to progamming (along with OO).
    You better get used to them 🙂

    Thanks for the code. Internet is great.

  2. Jarl E. Gjessing

    Ends up in a infinite loop when I call it 😦

  1. Pingback: Best-of-the-Web 9 | davblog: webdev and stuff

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: