extractFromSource($source); } public function extractFromSource($source) { $tokens = token_get_all($source); $comment = ''; $eligible = 0; $out = array(); foreach ($tokens as $key=>$token) { list($token, $content, $line) = $token; /* echo "[$line] "; if (is_long($token)) { echo token_name($token) . ': '; } echo htmlspecialchars($content); echo "\n"; */ switch ($token) { case T_DOC_COMMENT: $comment = $content; break; case T_PUBLIC: case T_STATIC: case T_FUNCTION: $eligible++; break; case T_STRING: if ($eligible > 2) { $out[] = array( $content, $comment ); $comment = ''; } $eligible = 0; break; case T_WHITESPACE: break; default: if ($comment) $comment = ''; break; } } return $out; } protected function parseDoc($method) { list($name, $comment) = $method; $out = array( 'name' => $name, 'params' => array(), 'return' => '', 'short_desc' => '', 'deprecated' => '', 'access' => '', 'example' => '', 'since' => '', ); $comment = preg_replace('!(?:^/\*\*+|\*/$)!', '', $comment); $comment = explode("\n", trim($comment)); $current = ''; $current_param = 0; foreach ($comment as $line) { $line = preg_replace('!^\s*\*+\s*!', '', trim($line)); if (preg_match('!^@([a-z]+)\s+(.*)$!', $line, $match)) { $current = $match[1]; switch ($match[1]) { case 'ignore': { return false; } case 'param': { if (preg_match('!^('.self::TYPE_REGEXP.')\s+\$([a-z0-9_-]+)\s+(.*)$!', $match[2], $submatch)) { $out['params'][] = array( 'type' => $submatch[1], 'name' => $submatch[2], 'desc' => $submatch[3], ); $current_param = count($out['params']) - 1; } break; } case 'return': { if (preg_match('!^('.self::TYPE_REGEXP.')(?:\s+(.+))?$!', $match[2], $submatch)) { $out['return'] = array('type' => $submatch[1], 'desc' => $submatch[2]); } break; } case 'deprecated': case 'deprec': $out['deprecated'] = $match[2]; break; case 'access': if (in_array($match[2], array('public', 'private', 'protected'))) { $out['access'] = $match[2]; } break; case 'example': $out['example'] = $match[2]; break; case 'since': $out['since'] = $match[2]; break; default: break; } } else { if (empty($line) && $current == 'short_desc') { $current = 'desc'; continue; } if (empty($current)) { $current = 'short_desc'; } switch ($current) { case 'short_desc': case 'desc': $out[$current] .= "\n" . $line; break; case 'return': $out[$current]['desc'] .= "\n" . $line; break; case 'param': $out['params'][$current_param]['desc'] .= "\n" . $line; break; default: break; } } } $out['short_desc'] = trim($out['short_desc']); $out['desc'] = trim($out['desc']); return $out; } public function getDocumentation($file) { $content = $this->extractFromFile($file); $out = array(); foreach ($content as $method) { if ($doc = $this->parseDoc($method)) $out[] = $doc; } return $out; } } ?>