Skip to content

HTML Comment Attribute Syntax ​

An alternative way to specify attributes using HTML comments instead of the code fence info string.

Why? ​

Adding attributes to the code fence info string (e.g., ```php ignore) can break syntax highlighting in editors like PHPStorm, VS Code, and others. These editors only recognize the language identifier (php) and treat anything else in the info string as unknown, disabling PHP-specific highlighting for the entire block.

HTML comment attributes solve this by moving attributes outside the code fence:

markdown
<!-- doctest-attr: ignore -->
```php
// Editor sees plain ```php — full syntax highlighting preserved
echo 'Hello, World!';
```

The rendered documentation looks identical — HTML comments are invisible to readers.

Syntax ​

markdown
<!-- doctest-attr: attribute1 key="value" attribute2 -->
```php
// your code here
```

The comment must appear on the line immediately before the code fence. If any other content (paragraphs, headings, etc.) appears between the comment and the fence, the comment is ignored.

Supported Attributes ​

AttributeHTML Comment Syntax
ignore<!-- doctest-attr: ignore -->
no_run<!-- doctest-attr: no_run -->
throws<!-- doctest-attr: throws -->
throws (class)<!-- doctest-attr: throws(RuntimeException) -->
throws (class + message)<!-- doctest-attr: throws(RuntimeException, "not found") -->
parse_error<!-- doctest-attr: parse_error -->
group<!-- doctest-attr: group="name" -->
setup<!-- doctest-attr: setup group="name" -->
teardown<!-- doctest-attr: teardown group="name" -->
bootstrap<!-- doctest-attr: bootstrap="laravel" -->
bootstrap (multiple)<!-- doctest-attr: bootstrap="laravel,database" -->

Multiple attributes can be combined in a single comment:

markdown
<!-- doctest-attr: setup group="db" bootstrap="laravel" -->
```php
$pdo = new PDO('sqlite::memory:');
```

Examples ​

Ignore ​

markdown
<!-- doctest-attr: ignore -->
```php
echo $config['key']; // Can't run standalone
```

No Run (syntax check only) ​

markdown
<!-- doctest-attr: no_run -->
```php
$users = DB::table('users')->where('active', true)->get();
```

Throws ​

markdown
<!-- doctest-attr: throws(InvalidArgumentException, "Division by zero") -->
```php
function divide(int $a, int $b): float {
    if ($b === 0) {
        throw new InvalidArgumentException('Division by zero');
    }
    return $a / $b;
}

divide(10, 0);
```

Group with setup ​

markdown
<!-- doctest-attr: setup group="cart" -->
```php
$cart = [];
```

<!-- doctest-attr: group="cart" -->
```php
$cart[] = ['item' => 'Widget', 'price' => 9.99];
echo count($cart);
```
<!-- doctest: 1 -->

Bootstrap ​

markdown
<!-- doctest-attr: bootstrap="laravel" -->
```php
$user = User::factory()->create();
echo $user->exists;
```
<!-- doctest: 1 -->

One Comment Per Block ​

Only one doctest-attr comment is allowed before each code block. Multiple comments throw a RuntimeException:

markdown
<!-- doctest-attr: group="first" -->
<!-- doctest-attr: bootstrap="laravel" -->
```php
echo 'hello';
```
RuntimeException: Multiple doctest-attr HTML comments found before code block. Use only one comment.

Combine all attributes into a single comment instead:

markdown
<!-- doctest-attr: group="first" bootstrap="laravel" -->
```php
echo 'hello';
```

Merging Rules ​

Both syntaxes can coexist in the same file — some blocks can use info string attributes, others can use HTML comment attributes.

However, a single block cannot have the same attribute from both sources. If both the info string and the HTML comment set the same attribute (e.g., both set group), DocTest throws a RuntimeException:

Conflicting group: info string has 'cart' but HTML comment has 'orders'. Use only one source.

Complementary attributes are fine — for example, group from the comment and setup from the info string:

markdown
<!-- doctest-attr: group="db" -->
```php setup
$pdo = new PDO('sqlite::memory:');
```

Released under the MIT License.