It is true that statements and declarations in PHP generally have an ending symbol. However, attributes are not a standalone statement or declaration, but rather modifiers on a declaration. They do not stand alone, but are always followed by a declaration with which the metadata is associated. This is similar to the public and static keywords that modify a method, or a type declaration that modifies a parameter. For example, we do not write:
[final] class X {
[public] function foo([int|float] $bar) {}
}
Attributes without an ending symbol are consistent with how these other declaration modifiers are written:
@@MyAttr("value")
final class X {
@@Jit
public function foo(@@Deprecated int|float $bar) {}
}
Attribute grouping could be considered helpful with the @[]
, #[]
,
and especially <<>>
syntaxes to reduce verbosity when adding
multiple attributes to a declaration.
However, it also has the downside of leading to unnecessary diff noise when adding/removing a second attribute on its own line. For example:
#[SomeAttribute("with argument")]
function foo() {}
// after adding second grouped attribute changes to:
#[
SomeAttribute("with argument"),
OtherAttr([1, 2, 3]),
]
function foo() {}
To avoid modifying lines for unchanged attributes, a coding style could mandate that the first attribute always be written like this:
#[
SomeAttribute("with argument"),
]
function foo() {}
But this also adds diff noise since from the beginning two extra lines are needed.
The @@
syntax is equally concise without grouping, and ensures
that individual attribute lines can always be added/removed without
modifying other attribute lines:
@@SomeAttribute("with parameter")
@@OtherAttr([1, 2, 3]) // this line can be added/removed independently
function foo() {}
The partial forward compatibility of #[]
would provide a temporary
benefit to library authors, who would be able to reuse the same class
as a PHP 8 attribute as well as to store annotation information when
the library is used on PHP 7. However, this benefit will be irrelevant
once most of the library users upgrade to PHP 8, and the library wants
to take advantage of any other PHP 8 syntax.
Even without partial syntax forward compatibility, a library can support both PHP 8 attributes and PHP 7 annotations with a small amount of extra work. A parent class can be used to store/handle docblock annotation info, and a child class can be registered as an attribute for PHP 8 users.
Long term we need to consider whether the #[]
syntax would continue
to result in confusion with hash comments (which have never been
deprecated).
A further downside of the partial forward compatibility is that when code intended for PHP 8 is run on PHP 7, instead of immediately failing it can continue running with different unexpected results. Consider these examples:
class X {
// This comments out the first parameter entirely in
// PHP 7, silently leading to different behavior.
public function __construct(
#[MyImmutable] public bool $x,
private bool $flag = false,
) {}
}
<?php
// This example echoes the rest of the source code in
// PHP 7 and echoes "Test" in PHP 8.
#[DeprecationReason('reason: <https://some-website/reason?>')]
function main() {}
const APP_SECRET = 'app-secret';
echo "Test\n";
If I had to choose between
@@
and@:
, I would choose the first one; I don't know why, but the latter does not look appealing to me.I was wondering...since people seems to feel comfortable with the use of single
@
sign, would there be an issue to suggest the use of_@
as a new annotation syntax?