Uniones etiquetadas en PHP (similar a Rust)

En el artículo anterior escribí sobre cómo agregar enumeraciones en PHP8.1. La votación fue exitosa, por lo que el tema puede considerarse resuelto.







Sin embargo, la implementación de enumeraciones es solo una parte del plan global . Hoy consideraremos el siguiente artículo, uniones etiquetadas, en ruso se traduce como "tipo-suma".







Aún no se ha votado , pero se propone incluirlo también en PHP 8.1.







Todos estos términos "tipos de datos algebraicos", "tipo de suma" suenan atemorizantes, pero en realidad todo es bastante simple.







¿Por qué es necesario todo esto?







Resultado como en óxido



Si ha escrito en Rust, probablemente se haya encontrado con la enumeración Result. En Rust, Go, etc. no existe un mecanismo de excepción, ya que estos lenguajes consideran que el manejo de errores explícitos es mucho más confiable. El lenguaje te obliga a resolver explícitamente todas las variantes de eventos y no lanzar una excepción con la esperanza de que alguien en la parte superior lo sepa y sepa cómo manejarlo correctamente. (No culpemos aquí, sobre el tema de las excepciones frente a los tipos de devolución, todos tienen su propia opinión). Hablando específicamente sobre Rust, el resultado de una llamada de función que puede generar un error a menudo se convierte en un valor de Resultado.







El resultado consta de dos variantes (casos en la terminología de enumeración de PHP): Ok y Err. Podríamos hacer variaciones usando la funcionalidad de enumeración anterior, o incluso constantes, pero también necesitamos devolver los valores en sí. Además, en caso de éxito, el valor puede ser una cadena y, en caso de error, algún otro tipo. Por ejemplo, entero (estado de respuesta HTTP).







Cómo se verá en PHP si la votación es exitosa:







enum Result {
    case Ok(public string $json);
    case Err(public int $httpStatus);
}

function requestApi($url): Result {
    //
}
      
      





ahora podemos transferir esta respuesta a otro lugar, y el conocimiento sobre el error y su tipo nunca se perderá.







Como escribí en el artículo anterior , enum es esencialmente una clase, puede tener métodos, etc. En el caso de una suma de tipos, los métodos pueden ser generales para toda la enumeración o para un caso específico.







Aquí hay una implementación de ejemplo de la mónada Maybe (ejemplo de RFC):







La Mónada Quizás



(En Rust, este tipo se llama Opción)







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 está interesado en artículos similares sobre desarrollo, en particular, ¿qué pasará a continuación con el patrón de coincidencia, suscríbase al canal de telegramas Cross Join !








All Articles