Definitions
A definition is what turns a raw @tag line into a tag object. There is exactly one per tag, and it declares two things: the shape of the line that follows @tagname, and how to build the tag from what that shape matched.
A definition is a TagDefinitionInterface implementation — in practice, almost always written by extending the TagDefinition base class, which takes care of the boilerplate and leaves only one method to fill in: create().
Take the @param tag, whose line is "@param" <Type> <Variable> [ <Description> ]:
The constructor hands the base class three things:
name— the canonical tag name, without the leading@.spec— the grammar of the line's body.placement— where the tag may appear (see below).
Building the Tag
create() receives a TagPayload carrying whatever the grammar captured, and returns the finished tag. $result->get('type') fetches a required capture (it throws if nothing was captured under that alias); $result->find('description') fetches an optional one, returning null when it did not match.
A tag body that does not match its spec at all never reaches create(): it becomes an InvalidTag before create() would even be called, so a definition never has to guard against a malformed match itself.
Inline Tags
Where a tag may appear is declared by the placement: argument, a TagPlacement enum with three cases:
A definition that omits the argument defaults to TagPlacement::Any. A tag whose placement allows it inline may be used, in addition to standing on its own line, nested inside a description as a {@tag ...} sequence with balanced braces — parsing it there produces the exact same kind of tag object either way.
Six built-in tags allow it: @see, @link, @internal and @example are Any, while @inheritdoc and @source are Inline-only. Every other tag, @param included, is declared Block and is never lifted out of running text: a {@param} written inside a sentence stays exactly as written, as plain text, rather than being parsed.