Невозможно передать нулевой аргумент при использовании подсказки типа

193

Следующий код:

<?php

    class Type {

    }

    function foo(Type $t) {

    }

    foo(null);

?>

не удалось во время выполнения:

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

Почему нельзя пропустить null, как и в других языках?

Абдулла
источник

Ответы:

357

PHP 7.1 или новее (выпущено 2 декабря 2016 г.)

Вы можете явно объявить переменную nullс этим синтаксисом

function foo(?Type $t) {
}

это приведет к

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

Итак, если вам нужен необязательный аргумент, вы можете следовать соглашению, Type $t = nullтогда как если вам нужно, чтобы аргумент принимал оба nullи его тип, вы можете следовать приведенному выше примеру.

Вы можете прочитать больше здесь .


PHP 7.0 или старше

Вы должны добавить значение по умолчанию, как

function foo(Type $t = null) {

}

Таким образом, вы можете передать ему нулевое значение.

Это задокументировано в разделе руководства по объявлениям типов :

Объявление может быть принято для принятия NULLзначений, если для параметра по умолчанию установлено значение NULL.

DonCallisto
источник
10
Так почему же нуль не является нулевым объектом ?
Pacerier
4
Большинство языков позволяют null иметь любой тип. По этому сценарию.
Генри
24
На мой взгляд, это плохая языковая конструкция. 1. В других языках нуль имеет возможность быть любого типа, что делает нуль допустимым аргументом в этом случае. 2: Php использует значение по умолчанию для аргумента, чтобы указать, что null допустим, это неясно, и это делает обязательный параметр невозможным, даже если разработчик хочет принудительно передать null в явном виде.
Генри
2
Я согласен с @Henry, кроме того, выглядит странно, что требуются параметры после того, что выглядит как необязательный параметр.
Герой Силы
6
Я согласен с @Henry только в отношении 2. Что касается того факта, что вы не можете передать null, function foo(Type $t)это ОЧЕНЬ хорошо; см. Null References: Ошибка в миллиард долларов
Константин Гальбену
36

Начиная с PHP 7.1, доступны обнуляемые типы , так как функции возвращают типы и параметры. Тип ?Tможет иметь значения указанного Типа Tили null.

Итак, ваша функция может выглядеть так:

function foo(?Type $t)
{

}

Как только вы сможете работать с PHP 7.1, эта нотация должна быть предпочтительнее function foo(Type $t = null) , потому что она по-прежнему заставляет вызывающую сторону явно указывать аргумент для параметра $t.

Оператор
источник
12

Пытаться:

function foo(Type $t = null) {

}

Проверьте аргументы функции PHP .

SeanWM
источник
11
Проблема, с которой я столкнулся, заключается в том, что она меняет определение функции. Теперь параметр является необязательным - что на самом деле не то, что задумал автор (хотя, если он передает его в ноль, это неявно необязательно).
раздавить
7

Как уже упоминалось в других ответах, это возможно, только если вы укажете nullзначение по умолчанию.

Но самым чистым типобезопасным объектно-ориентированным решением будет 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)';
    }
}

Использование:

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);
Фабиан Шменглер
источник
1
Этот подход часто нецелесообразен, потому что вместо 1 класса вам теперь нужно 3. Кроме того, он заставляет автора NullFooпереопределять абстрактные методы, даже если они не имеют значения (по определению null).
Оператор
1
По моему опыту, шаблон NullObject может быть практичным, если вы работаете в целом очень строго, классическим ОО. В ответ, имхо, шаблон NullObject немного злоупотреблен, так как он специально предназначен для того, чтобы избегать if (something is null)проверок, так как NullObject предназначен для охвата всего поведения несуществующего значения, и любой сторонний соавтор не должен интересоваться, является ли объект не существует (ноль) или нет.
проиграл