No se puede pasar un argumento nulo cuando se utilizan sugerencias de tipo

193

El siguiente código:

<?php

    class Type {

    }

    function foo(Type $t) {

    }

    foo(null);

?>

falló en tiempo de ejecución:

PHP Fatal error:  Argument 1 passed to foo() must not be null

¿Por qué no se permite pasar nulo al igual que otros idiomas?

Abdullah
fuente

Respuestas:

357

PHP 7.1 o más reciente (lanzado el 2 de diciembre de 2016)

Puede declarar explícitamente una variable nullcon esta sintaxis

function foo(?Type $t) {
}

esto resultará en

$this->foo(new Type()); // ok
$this->foo(null); // ok
$this->foo(); // error

Entonces, si desea un argumento opcional, puede seguir la convención, Type $t = nullmientras que si necesita hacer que un argumento acepte ambos nully su tipo, puede seguir el ejemplo anterior.

Puedes leer más aquí .


PHP 7.0 o anterior

Tienes que agregar un valor predeterminado como

function foo(Type $t = null) {

}

De esa manera, puede pasarle un valor nulo.

Esto está documentado en la sección del manual sobre declaraciones de tipo :

La declaración se puede hacer para aceptar NULLvalores si el valor predeterminado del parámetro se establece en NULL.

Don Calisto
fuente
10
Entonces, ¿por qué no es nulo el objeto nulo ?
Pacerier
44
La mayoría de los idiomas permiten que null tenga cualquier tipo. En este escenario.
Henry
24
En mi opinión, esta es una construcción de lenguaje pobre. 1. En otros idiomas, nulo tiene la capacidad de ser de cualquier tipo, lo que convierte a nulo en un argumento válido en este caso. 2: Php está usando un valor predeterminado para un argumento para especificar que nulo está permitido, esto es oscuro y hace imposible un parámetro obligatorio incluso si el desarrollador quiere forzar que se pase explícitamente un nulo.
Henry
2
Estoy de acuerdo con @Henry, además parece extraño tener los parámetros requeridos después de lo que parece un parámetro opcional.
Force Hero
66
Estoy de acuerdo con @Henry solo en 2. En cuanto a 1, el hecho de que no se puede pasar nulo function foo(Type $t)es algo MUY bueno; ver Referencias nulas: El error del billón de dólares
Constantin Galbenu
36

A partir de PHP 7.1, los tipos anulables están disponibles, tanto los tipos de retorno de función como los parámetros. El tipo ?Tpuede tener valores del tipo especificado T, o null.

Entonces, su función podría verse así:

function foo(?Type $t)
{

}

Tan pronto como pueda trabajar con PHP 7.1, debería preferirse esta notación function foo(Type $t = null), ya que aún obliga al llamante a especificar explícitamente un argumento para el parámetro $t.

El operador
fuente
12

Tratar:

function foo(Type $t = null) {

}

Echa un vistazo a los argumentos de la función PHP .

SeanWM
fuente
11
El problema que tengo con esto es que cambia la definición de la función. Ahora el parámetro es opcional, que no es realmente lo que pretendía el autor (aunque, si lo pasa como nulo, es implícitamente opcional).
aplastar
7

Como ya se mencionó en otras respuestas, esto solo es posible si especifica nullcomo valor predeterminado.

Pero la solución orientada a objetos de tipo seguro más limpia sería un NullObject :

interface FooInterface
{
    function bar();
}
class Foo implements FooInterface
{
    public function bar()
    {
        return 'i am an object';
    }
}
class NullFoo implements FooInterface
{
    public function bar()
    {
        return 'i am null (but you still can use my interface)';
    }
}

Uso:

function bar_my_foo(FooInterface $foo)
{
    if ($foo instanceof NullFoo) {
        // special handling of null values may go here
    }
    echo $foo->bar();
}

bar_my_foo(new NullFoo);
Fabian Schmengler
fuente
1
Este enfoque a menudo no es práctico, porque en lugar de 1 clase, ahora necesita 3. Además, obliga al escritor de NullFooanular los métodos abstractos, a pesar de que no tienen significado (por definición de null).
TheOperator
1
En mi experiencia, el patrón NullObject puede ser práctico, si trabajas en general de una manera OO muy estricta y clásica. En la respuesta, en mi opinión, se abusa un poco del patrón NullObject, ya que está especialmente destinado a evitar if (something is null)verificaciones, ya que el NullObject está destinado a cubrir todo el comportamiento de un valor no existente y cualquier colaborador externo no debería estar interesado en saber si un objeto no existe (nulo) o no.
perdido el