Tipos de retorno anulables en PHP7

159

PHP 7 presenta declaraciones de tipo de retorno . Lo que significa que ahora puedo indicar que el valor de retorno es una determinada clase, interfaz, matriz, invocable o uno de los tipos escalares recién imprimibles, como es posible para los parámetros de función.

function returnHello(): string {
    return 'hello';
}

A menudo sucede que un valor no siempre está presente y que puede devolver algo de algún tipo o nulo. Si bien puede hacer que los parámetros sean anulables estableciendo su valor predeterminado en nulo ( DateTime $time = null), no parece haber una forma de hacerlo para los tipos de retorno. ¿Es ese el caso, o de alguna manera no encuentro cómo hacerlo? Estos no funcionan:

function returnHello(): string? {
    return 'hello';
}

function returnHello(): string|null {
    return 'hello';
}
Jeroen De Dauw
fuente
8
PHP7 todavía no permitirá tipos de retorno anulables, pero hay un RFC que tiene como objetivo abordar esto en PHP 7.1 aquí . La notación propuesta seríafunction returnString(?string $stringNull) : ?string { return $stringNull;}
Elias Van Ootegem el
1
Terminé emulando la nulabilidad al abusar de las excepciones en mi aplicación por ahora. Si también estás de acuerdo con ser tonto, esto podría ser útil: github.com/JeroenDeDauw/OhMyPhp/blob/master/src/…
Jeroen De Dauw
Quizás tenga más sentido usar la Trowableinterfaz PHP7 (específicamente, extender la TypeError)
Elias Van Ootegem

Respuestas:

258

PHP 7.1 ahora admite tipos de retorno anulables . El primer RFC al que me vinculé es el que eligieron:

function nullOrString(int $foo) : ?string
{
    return $foo%2 ? "odd" : null;
}

vieja respuesta:

Como mi comentario fue en realidad una respuesta a la pregunta:

PHP 7 todavía no admitirá tipos de retorno anulables, pero hay un RFC para abordar eso, apunta a aterrizar en PHP 7.1. Si se aprueba, la sintaxis afectaría a todas las sugerencias de tipo (tanto los tipos de retorno como las sugerencias de tipo):

public function returnStringOrNull(?array $optionalArray) : ?string
{
    if ($optionalArray) {
        return implode(', ', $optionalArray);//string returned here
    }
    return null;
}

También hay una RFC competitiva para agregar tipos de unión, que podría hacer lo mismo, pero se vería diferente:

public function returnStringOrNull(array|null $optionalArray) : string|null
{
    if ($optionalArray) {
        return implode(', ', $optionalArray);//string returned here
    }
    return null;
}

Por ahora, sin embargo, tendrás que escribir:

public function returnStringOrNull( array $optionalArray = null)
{
    if ($optionalArray) {
        return implode(', ', $optionalArray);
    }
}

O simplemente devuelva una cadena vacía para que sea consistente con el tipo de retorno, y verifique el valor falso:

public function returnStringOrNull( array $optionalArray = null) : string
{
    if ($optionalArray) {
        return implode(', ', $optionalArray);
    }
    return '';
}
//call
$string = $x->returnStringOrNull();
if (!$string) {
    $string = $x->returnStringOrNull(range(1, 10));
}
Elias Van Ootegem
fuente
55
PHP 7 won't support nullable return-types just yet, but there's an RFC out to address just that- Sí, RFC, "todavía". No me malinterpreten: soy un gran usuario de PHP desde PHP3 realmente horrible hasta ahora, sin vacíos, pero cuando vi todos estos RFC que rechazaron por 7, mi impresión fue simplemente "¡¿WTF ?!". Los usuarios ven el desorden y están dispuestos a limpiarlo de forma compatible con versiones anteriores y simplemente obtienen "no". ¿Métodos limpios nombrando desorden? ¿Arreglado nullno ser ciudadano demasiado especial? No, no es necesario ¿Agregar opción para hacer que todo sea sensible a mayúsculas y minúsculas? Nah ... Y luego, sorprende que la gente cambie.
Marcin Orlowski
1
@MarcinOrlowski: una sugerencia de tipo de retorno anulable tendría sentido. He seguido un par de RFC durante 7, y estuve de acuerdo en su mayor parte con rechazar muchos de ellos. Los cambios en los que se estaban centrando no estaban tanto en el lenguaje como en el tiempo de ejecución y el compilador. Para algunos de los RFC que se rechazaron, vale la pena leer los hilos de discusión para comprender por qué eligieron no implementar esos cambios (por ejemplo, desaprobar var). Lo que es lamentable es que, en cambio, aceptaron demasiados productos agradables (operador de nave espacial, por ejemplo)
Elias Van Ootegem
@EliasVanOotegem Los tipos anulables ahora se admiten correctamente, ya que 7.1 se lanzó el 1 de diciembre.
lonesomeday
@lonesomeday: De hecho, agregó el enlace + ejemplo básico al final de mi respuesta
Elias Van Ootegem
mmm ish un buen tipo para actualizar esta respuesta! es decir, el tipo de unión no parece ser compatible con PHP 7.1
Dennis
67

Los tipos anulables están disponibles en PHP 7.1.

Este es un ejemplo de sintaxis:

public function getName(): ?string
{
    return $this->name; // name can be null
}

PHP 7.1 ahora es GA y puede actualizar desde PHP 7.0 (solo hay algunos cambios incompatibles con versiones anteriores que debe verificar)

Las nueces
fuente
22
En mi opinión, es una broma entregar declaraciones de tipo de retorno sin implementar "nullable". Los tipos de retorno no se pueden usar hasta que se implemente la característica "anulable".
joonas.fi
2
@ joonas.fi Los valores de retorno estrictamente escritos de la OMI siempre deben ser de ese tipo, un retorno nulo no se mantiene en ese contrato y debería arrojar una excepción que dé más significado a la razón de un valor nulo.
Steve Buzonas el
8
@SteveBuzonas si considera un método getAgeInYears () en un objeto que representa a una Persona, ¿cómo modelaría a una persona que no nos ha dicho su edad? Volver nulo? ¿Devolver 0? Devolver nulo semánticamente significa "no sabemos", mientras que 0 semánticamente significa "la persona tiene 0 años". Por lo tanto, diría que getAgeInYears ():? Int es el mejor diseño. Las excepciones de lanzamiento deben reservarse para ... casos excepcionales. No conocer la edad de una persona en la mayoría de los sistemas no debe considerarse un caso excepcional.
joonas.fi
@ joonas.fi muy cierto, y esa es una práctica común. Sin embargo, su implementación ahora debe ser consciente de que el campo es anulable y se maneja explícitamente en consecuencia. Lo que muy bien puede ser hacer x, excepto cuando es nulo, que podría implementarse fácilmente con un try / catch. Además, si uno realmente requiriera un valor en ese campo anulable para continuar la ejecución, una excepción es probablemente una mejor opción.
Steve Buzonas
Me di cuenta de que esta sintaxis hace que PHPMD arroje muchos errores. Esperemos que lo arreglen pronto.
Tom Jowitt
0

Funciona con cualquier tipo.
Ejemplo:

public function getOpportunity(): ?Opportunity
{
    return $this->opportunity;
}
Bayma Bruno
fuente