Eyes, JAPAN
PHP 8 new features — Attributes & Match
Tang
1. Attributes
Before talking about the annotations, let us talk about the previous annotations. We often see these in PHP projects, similar to the following @param and @see:
/**
* @param User $argument
* @see https:/xxxxxxxx/xxxx/xxx.html
*/
function getData($User) {}
This is called a comment. For the previous PHP, @param and @see in the comment are meaningless. The entire paragraph will be saved as a function with a string called doc_comment.
If we want to analyze the meaning of this comment, we need to design some specific syntax, such as @+name in the case, similar to @param, and then analyze this string by ourselves to extract the corresponding information.
For example, if we want to get the information of See this annotation, we need to do something like:
$ref = new ReflectionFunction("getData");
$doc = $ref->getDocComment();
$see = substr($doc, strpos($doc, "@see") + strlen("@see "));
Such character string processing is relatively troublesome and error-prone.
As for Attributes, in fact, “comments” are upgraded to “notes” that support formatted content.
such as:
#[Params("User", "argument")]
#[See("https://xxxxxxxx/xxxx/xxx.html")]
function getData($argument) {}
When there are multiple comments, you can also write:
#[
Params("User", "argument"),
See("https://xxxxxxxx/xxxx/xxx.html")
]
function getData($argument) {}
Don’t worry about the meaning of writing this way. From a functional point of view, you can now get this formatted comment through Reflection. For example, we want to get the comment of See now:
$ref = new ReflectionFunction("getData");
var_dump($ref->getAttributes("See")[0]->getName());
var_dump($ref->getAttributes("See")[0]->getArguments());
Output is:
string(3) "See"
array(1) {
[0]=>
string(30) "https://xxxxxxxx/xxxx/xxx.html"
}
Of course, there is a slightly more advanced usage, that is, you can define a so-called “annotation class”:
#[Attribute(Attribute::TARGET_FUNCTION)]
class MyAttribute {
publicfunction__construct($name, $value) {
var_dump($name);
var_dump($value);
}
}
#[MyAttribute("See", "https://xxxxxxxx/xxxx/xxx.html")]
function getData($argument) {}
$ref = new ReflectionFunction("getData");
$ref->getAttributes("MyAttribute")[0]->newInstance();
The __construct method of MyAttribute is called, and the parameters passed in the call are “See” and “https://xxxxxxxx/xxxx/xxx.html”
2. Match
In the past, we may often use switch to do value conversion work, such as:
switch ($input) {
case"true":
$result = 1;
break;
case"false":
$result = 0;
break;
case"null":
$result = NULL;
break;
}
Then if you use the match keyword, it can become:
$result = match($input) {
"true"=>1,
"false"=>0,
"null"=>NULL,
};
Compared with switch, match will return the value directly, which can be directly assigned to $result.
And, similar to multiple case and block of switch, multiple conditions of match can also be written together, such as:
$result = match($input) {
"true", "on"=>1,
"false", "off"=>0,
"null", "empty", "NaN"=>NULL,
};
It should be noted that the difference from switch is that we may often encounter this kind of weird problem when using switch:
$input = "2 person";
switch ($input) {
case2:
echo"bad";
break;
}
You will find that bad is actually output because the switch uses loose comparison (==). Match will not have this problem, it uses strict comparison (===), that is, the value and type must be exactly equal.
Also, when the input cannot be satisfied by all the conditions in the match, match will throw an UnhandledMatchError exception:
$input = "false";
$result = match($input) {
"true"=>1,
};
Output:
Fatal error: Uncaught UnhandledMatchError: Unhandled match value of type string.
In this way, there is no need to worry about unpredictable errors in case the match conditions are not written.
In addition, it should be noted that match is a keyword, that is, it cannot appear in namespace or class name since PHP8