3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Code\Scanner
;
12 use Zend\Code\Annotation\AnnotationManager
;
13 use Zend\Code\NameInformation
;
15 class DocBlockScanner
implements ScannerInterface
20 protected $isScanned = false;
25 protected $docComment = null;
28 * @var NameInformation
30 protected $nameInformation = null;
33 * @var AnnotationManager
35 protected $annotationManager = null;
40 protected $shortDescription = null;
45 protected $longDescription = '';
50 protected $tags = array();
55 protected $annotations = array();
58 * @param string $docComment
59 * @param null|NameInformation $nameInformation
61 public function __construct($docComment, NameInformation
$nameInformation = null)
63 $this->docComment
= $docComment;
64 $this->nameInformation
= $nameInformation;
70 public function getShortDescription()
74 return $this->shortDescription
;
80 public function getLongDescription()
84 return $this->longDescription
;
90 public function getTags()
100 public function getAnnotations()
104 return $this->annotations
;
110 protected function scan()
112 if ($this->isScanned
) {
118 $tokens = $this->tokenize();
123 $token = current($tokens);
126 case 'DOCBLOCK_NEWLINE':
127 if ($this->shortDescription
!= '' && $tagIndex === null) {
130 $this->longDescription
.= $token[1];
132 goto SCANNER_CONTINUE
;
134 case 'DOCBLOCK_WHITESPACE':
135 case 'DOCBLOCK_TEXT':
136 if ($tagIndex !== null) {
137 $this->tags
[$tagIndex]['value'] .= ($this->tags
[$tagIndex]['value'] == '') ?
$token[1] : ' ' . $token[1];
138 goto SCANNER_CONTINUE
;
139 } elseif ($mode <= 2) {
141 $this->shortDescription
.= $token[1];
143 $this->longDescription
.= $token[1];
145 goto SCANNER_CONTINUE
;
148 array_push($this->tags
, array('name' => $token[1],
151 $tagIndex = key($this->tags
);
153 goto SCANNER_CONTINUE
;
155 case 'DOCBLOCK_COMMENTEND':
161 if (next($tokens) === false) {
168 $this->shortDescription
= trim($this->shortDescription
);
169 $this->longDescription
= trim($this->longDescription
);
170 $this->isScanned
= true;
176 protected function tokenize()
178 static $CONTEXT_INSIDE_DOCBLOCK = 0x01;
179 static $CONTEXT_INSIDE_ASTERISK = 0x02;
182 $stream = $this->docComment
;
190 $MACRO_STREAM_ADVANCE_CHAR = function ($positionsForward = 1) use (&$stream, &$streamIndex, &$currentChar, &$currentWord, &$currentLine) {
191 $positionsForward = ($positionsForward > 0) ?
$positionsForward : 1;
192 $streamIndex = ($streamIndex === null) ?
0 : $streamIndex +
$positionsForward;
193 if (!isset($stream[$streamIndex])) {
194 $currentChar = false;
198 $currentChar = $stream[$streamIndex];
200 $currentLine = (preg_match('#(.*?)\r?\n#', $stream, $matches, null,
201 $streamIndex) === 1) ?
$matches[1] : substr($stream, $streamIndex);
202 if ($currentChar === ' ') {
203 $currentWord = (preg_match('#( +)#', $currentLine, $matches) === 1) ?
$matches[1] : $currentLine;
205 $currentWord = (($matches = strpos($currentLine, ' ')) !== false) ?
substr($currentLine, 0, $matches) : $currentLine;
210 $MACRO_STREAM_ADVANCE_WORD = function () use (&$currentWord, &$MACRO_STREAM_ADVANCE_CHAR) {
211 return $MACRO_STREAM_ADVANCE_CHAR(strlen($currentWord));
213 $MACRO_STREAM_ADVANCE_LINE = function () use (&$currentLine, &$MACRO_STREAM_ADVANCE_CHAR) {
214 return $MACRO_STREAM_ADVANCE_CHAR(strlen($currentLine));
216 $MACRO_TOKEN_ADVANCE = function () use (&$tokenIndex, &$tokens) {
217 $tokenIndex = ($tokenIndex === null) ?
0 : $tokenIndex +
1;
218 $tokens[$tokenIndex] = array('DOCBLOCK_UNKNOWN', '');
220 $MACRO_TOKEN_SET_TYPE = function ($type) use (&$tokenIndex, &$tokens) {
221 $tokens[$tokenIndex][0] = $type;
223 $MACRO_TOKEN_APPEND_CHAR = function () use (&$currentChar, &$tokens, &$tokenIndex) {
224 $tokens[$tokenIndex][1] .= $currentChar;
226 $MACRO_TOKEN_APPEND_WORD = function () use (&$currentWord, &$tokens, &$tokenIndex) {
227 $tokens[$tokenIndex][1] .= $currentWord;
229 $MACRO_TOKEN_APPEND_WORD_PARTIAL = function ($length) use (&$currentWord, &$tokens, &$tokenIndex) {
230 $tokens[$tokenIndex][1] .= substr($currentWord, 0, $length);
232 $MACRO_TOKEN_APPEND_LINE = function () use (&$currentLine, &$tokens, &$tokenIndex) {
233 $tokens[$tokenIndex][1] .= $currentLine;
236 $MACRO_STREAM_ADVANCE_CHAR();
237 $MACRO_TOKEN_ADVANCE();
241 if ($context === 0x00 && $currentChar === '/' && $currentWord === '/**') {
242 $MACRO_TOKEN_SET_TYPE('DOCBLOCK_COMMENTSTART');
243 $MACRO_TOKEN_APPEND_WORD();
244 $MACRO_TOKEN_ADVANCE();
245 $context |
= $CONTEXT_INSIDE_DOCBLOCK;
246 $context |
= $CONTEXT_INSIDE_ASTERISK;
247 if ($MACRO_STREAM_ADVANCE_WORD() === false) {
253 if ($context & $CONTEXT_INSIDE_DOCBLOCK && $currentWord === '*/') {
254 $MACRO_TOKEN_SET_TYPE('DOCBLOCK_COMMENTEND');
255 $MACRO_TOKEN_APPEND_WORD();
256 $MACRO_TOKEN_ADVANCE();
257 $context &= ~
$CONTEXT_INSIDE_DOCBLOCK;
258 if ($MACRO_STREAM_ADVANCE_WORD() === false) {
264 if ($currentChar === ' ' ||
$currentChar === "\t") {
265 $MACRO_TOKEN_SET_TYPE(($context & $CONTEXT_INSIDE_ASTERISK) ?
'DOCBLOCK_WHITESPACE' : 'DOCBLOCK_WHITESPACE_INDENT');
266 $MACRO_TOKEN_APPEND_WORD();
267 $MACRO_TOKEN_ADVANCE();
268 if ($MACRO_STREAM_ADVANCE_WORD() === false) {
274 if ($currentChar === '*') {
275 if (($context & $CONTEXT_INSIDE_DOCBLOCK) && ($context & $CONTEXT_INSIDE_ASTERISK)) {
276 $MACRO_TOKEN_SET_TYPE('DOCBLOCK_TEXT');
278 $MACRO_TOKEN_SET_TYPE('DOCBLOCK_ASTERISK');
279 $context |
= $CONTEXT_INSIDE_ASTERISK;
281 $MACRO_TOKEN_APPEND_CHAR();
282 $MACRO_TOKEN_ADVANCE();
283 if ($MACRO_STREAM_ADVANCE_CHAR() === false) {
289 if ($currentChar === '@') {
290 $MACRO_TOKEN_SET_TYPE('DOCBLOCK_TAG');
291 $MACRO_TOKEN_APPEND_WORD();
292 $MACRO_TOKEN_ADVANCE();
293 if ($MACRO_STREAM_ADVANCE_WORD() === false) {
299 if ($currentChar === "\n") {
300 $MACRO_TOKEN_SET_TYPE('DOCBLOCK_NEWLINE');
301 $MACRO_TOKEN_APPEND_CHAR();
302 $MACRO_TOKEN_ADVANCE();
303 $context &= ~
$CONTEXT_INSIDE_ASTERISK;
304 if ($MACRO_STREAM_ADVANCE_CHAR() === false) {
310 $MACRO_TOKEN_SET_TYPE('DOCBLOCK_TEXT');
311 $MACRO_TOKEN_APPEND_LINE();
312 $MACRO_TOKEN_ADVANCE();
313 if ($MACRO_STREAM_ADVANCE_LINE() === false) {