Dans l' article précédent, j'ai écrit sur l'ajout d'énumérations dans PHP8.1. Le vote a réussi, donc la question peut être considérée comme réglée.
Cependant, cela énumère la mise en œuvre n'est qu'une partie du plan global . Aujourd'hui, nous allons examiner l'élément suivant, les unions étiquetées, en russe, il se traduit par "type-sum".
Il n'a pas encore été voté , mais il est proposé de l'inclure également dans PHP 8.1.
Tous ces termes «types de données algébriques», «type somme» semblent effrayants, mais en réalité tout est assez simple.
Pourquoi tout cela est-il nécessaire?
Résultat comme dans la rouille
Si vous avez écrit en Rust, vous avez probablement rencontré l'énumération intégrée Result. Dans Rust, Go, etc. il n'y a pas de mécanisme d'exception, puisque ces langages considèrent la gestion des erreurs explicite comme beaucoup plus fiable. Le langage vous oblige à élaborer explicitement toutes les variantes d'événements et à ne pas lancer d'exception dans l'espoir que quelqu'un au sommet le sache et sache comment le gérer correctement. (Ne blâmons pas ici, sur le thème des exceptions vs types de retour, chacun a sa propre opinion). Parlant spécifiquement de Rust, le résultat d'un appel de fonction qui peut générer une erreur se transforme souvent en valeur Result.
Le résultat se compose de deux variantes (cas dans la terminologie PHP enum): Ok et Err. Nous pourrions faire des variations en utilisant la fonctionnalité d'énumération précédente, ou même des constantes, mais nous devons également renvoyer les valeurs elles-mêmes. De plus, en cas de succès, la valeur peut être une chaîne, et en cas d'erreur, un autre type. Par exemple, entier (état de la réponse HTTP).
À quoi cela ressemblera en PHP si le vote est réussi:
enum Result {
case Ok(public string $json);
case Err(public int $httpStatus);
}
function requestApi($url): Result {
//
}
maintenant nous pouvons transférer cette réponse ailleurs, et la connaissance de l'erreur et de son type ne sera jamais perdue.
Comme je l'ai écrit dans l'article précédent , enum est essentiellement une classe, elle peut avoir des méthodes, etc. Dans le cas d'une somme de types, les méthodes peuvent être soit générales pour toute l'énumération, soit pour un cas spécifique.
Voici un exemple d'implémentation de la monade Maybe (exemple de RFC):
La monade peut-être
(Dans Rust, ce type est appelé Option)
enum Maybe {
// This is a Unit Case.
case None {
public function bind(callable $f)
{
return $this;
}
};
// This is a Tagged Case.
case Some(private mixed $value) {
// Note that the return type can be the Enum itself, thus restricting the return
// value to one of the enumerated types.
public function bind(callable $f): Maybe
{
// $f is supposed to return a Maybe itself.
return $f($this->value);
}
};
// This method is available on both None and Some.
public function value(): mixed {
if ($this instanceof None) {
throw new Exception();
}
return $this->val;
}
}
, : Some None, Some , None — None. bind. value()
RFC ,
$a = Maybe::Some("blabla");
// $a = Maybe::None
$a->bind();
, - Result Maybe , - . pattern matching, RFC, . , :
$result = requestApi($url);
if ($result is Result::Some {%$json}) {
// $json
}
if ($result is Result::Err {%$httpStatus}) {
// $httpStatus
}
, match.
, tagged unions. , - , , tokenizer (scanner), . : , enum. , , , . . :
enum Token {
case Comma;
case LeftBrace;
case RightBrace;
case StringLiteral(public string $str);
case Identifier(public string $identifier);
// ..
}
?
, RFC , , . , "" . tagged unions, , pattern matching.
Si vous êtes intéressé par des articles similaires sur le développement, en particulier, que se passera-t-il ensuite avec le modèle correspondant, abonnez-vous à la chaîne de télégramme Cross Join !