@@ -266,11 +266,21 @@ function export_docblock( $element, array $inherited_setup_blueprints = array(),
266266
267267 /*
268268 * phpDocumentor can split one fenced block across its short and long
269- * descriptions, alter its line structure, and parse `@` code as tags. If
270- * either description contains a possible fence, recover the original
271- * DocBlock before tokenizing it below. File reflectors require slicing the
272- * comment from the file contents; node-backed reflectors use the raw comment
273- * captured above.
269+ * descriptions, alter its line structure, and parse `@` code as tags. For
270+ * example, this source:
271+ *
272+ * ```php interactive
273+ * <?php
274+ *
275+ * echo 'before';
276+ * @unlink( '/tmp/example' );
277+ * ```
278+ *
279+ * can leave the opening lines in the short description, the `echo` line in the
280+ * long description, and `@unlink` in the tag list. If either description
281+ * contains a possible fence, recover the original DocBlock before tokenizing
282+ * it below. File reflectors require slicing the comment from the file contents;
283+ * node-backed reflectors use the raw comment captured above.
274284 */
275285 if ( false !== strpos ( $ short_description , '``` ' ) || false !== strpos ( $ raw_long_description , '``` ' ) ) {
276286 if ( $ element instanceof File_Reflector ) {
@@ -300,13 +310,19 @@ function export_docblock( $element, array $inherited_setup_blueprints = array(),
300310 }
301311
302312 if ( null !== $ source_docblock ) {
303- // phpDocumentor treats any line beginning with `@` as a tag, even
304- // inside a fenced block, and splits its short description at paragraph
305- // boundaries inside fences. Recover the description directly from the
306- // source comment so runnable code retains its source line structure. Stop
307- // at the first real tag outside a fence. Keep track of tag-looking code
308- // lines so the parsed DocBlock tags below can omit phpDocumentor's false
309- // positives without hiding real tags with the same name.
313+ /*
314+ * Recover exact description lines from source and stop at the first tag
315+ * outside a fence. For example:
316+ *
317+ * ```php
318+ * @since( 'inside-fence' );
319+ * ```
320+ * @since 1.0.0
321+ *
322+ * The first `@since` remains snippet code; the second ends the description.
323+ * Record the first name so only phpDocumentor's false in-fence tag is
324+ * removed from the parsed tags, leaving the real `@since 1.0.0` tag.
325+ */
310326 $ source_docblock = preg_replace ( "/ \r\n?/ " , "\n" , $ source_docblock );
311327 $ source_docblock = preg_replace ( '/\A[ \t]*\/\*\*[ \t]?/ ' , '' , $ source_docblock );
312328 $ source_docblock = preg_replace ( '/[ \t]*\*\/[ \t]*\z/ ' , '' , $ source_docblock );
@@ -320,9 +336,6 @@ function export_docblock( $element, array $inherited_setup_blueprints = array(),
320336 $ source_fences = tokenize_docblock_code_fences ( implode ( "\n" , $ source_lines ) );
321337 $ source_fence_index = 0 ;
322338 $ description_lines = array ();
323- // phpDocumentor starts its tag block at an optionally indented @ followed
324- // by a letter. Once started, only a column-zero @ with any valid tag name
325- // opens another tag; indented lines extend the preceding tag instead.
326339 $ parsed_tag_block_started = false ;
327340 foreach ( $ source_lines as $ source_line_number => $ source_line ) {
328341 while (
@@ -334,6 +347,13 @@ function export_docblock( $element, array $inherited_setup_blueprints = array(),
334347 $ is_in_fence = isset ( $ source_fences [ $ source_fence_index ] ) &&
335348 $ source_line_number > $ source_fences [ $ source_fence_index ]['start ' ];
336349
350+ /*
351+ * Before tag parsing starts, `^[ \t]*` permits indentation and `\pL`
352+ * requires a Unicode letter: ` @since` matches, while `@_before` does not.
353+ * Once started, `^@` requires column zero and the broader name class permits
354+ * an initial underscore or digit: `@_same` and `@2inside` match, while
355+ * ` @author` remains part of the preceding tag.
356+ */
337357 $ tag_pattern = $ parsed_tag_block_started
338358 ? '/^@([\w\-_ \\\\]+)/u '
339359 : '/^[ \t]*@([\pL][\w\-_ \\\\]*)/u ' ;
0 commit comments