Подтвердить что ты не робот

Почему переопределение параметров метода является нарушением строгих стандартов в PHP?

Я знаю, что в StackOverflow есть несколько подобных вопросов, например этот вопрос.

Почему переопределение параметров метода является нарушением строгих стандартов в PHP? Например:

class Foo
{
    public function bar(Array $bar){}
}

class Baz extends Foo
{
    public function bar($bar) {}
}

Строгие стандарты: декларация Baz:: bar() должна быть совместима с Foo:: bar()

На других языках программирования ООП вы можете. Почему это плохо в PHP?

4b9b3361

Ответ 1

В OOP SOLID означает Единая ответственность, Open-closed, замена Liskov, сегрегация интерфейса и инверсия зависимостей.

Принцип подстановки Liskov утверждает, что в компьютерной программе, если Бар является подтипом Foo, тогда объекты типа Foo можно заменить объектами типа Бар без изменения каких-либо желательных свойств этой программы (правильность, выполняемая задача и т.д.).

В сильно типизированных языках программирования при переопределении метода Foo, если вы изменяете подпись в баре, вы фактически перегружаетесь, поскольку исходный метод и новый метод доступны с разными сигнатурами. Поскольку PHP слабо типизирован, этого достичь невозможно, потому что компилятор не может знать, какой из методов вы на самом деле вызываете. (отсюда и причина, по которой у вас не может быть 2 метода с тем же именем, даже если их подписи разные).

Итак, чтобы избежать нарушения принципа Liskov Substitition, выдается строгая стандартная предупредительная надпись, говорящая программисту, что что-то может сломаться из-за изменения сигнатуры метода в дочернем классе.

Ответ 2

Я знаю, что опаздываю на вечеринку, но ответы на самом деле не говорят о реальной проблеме.

Проблема заключается в том, что PHP не поддерживает перегрузку функции/метода. Было бы сложно поддерживать перегрузку функций в нетипизированном языке.

Подсказка помогает. но в PHP он очень ограничен. Не знаю, почему. Например, вы не можете намекать, что переменная - это int или Boolean yet array. Пойдите фигурой!

Другие ориентированные на объект языки реализуют это с помощью перегрузки функций. То есть подпись функции явно отличается.

Так, например, если бы было возможно следующее: у нас не было бы проблемы

class Foo
{
    public function bar(Array $bar){
        echo "Foo::bar";
    }
}

class Baz extends Foo
{
    public function bar(int $bar) {
        echo "Baz::bar";
    }
}


$foo = new Baz();
$bar = new Baz();
$ar = array();
$i = 100;

$foo->bar($ar);
$bar->bar((int)$i);

would output

Foo::bar
Baz::bar

Конечно, когда дело дошло до конструкторов, разработчики php поняли, что им нужно это реализовать, нравится это или нет! Поэтому они просто подавляют ошибку или не поднимают ее в первом случае.

Это глупо.

Один знакомый однажды сказал, что PHP реализовал объекты только как способ реализации пространств имен. Теперь я не настолько критичен, но некоторые из принятых решений, как правило, поддерживают эту теорию.

У меня всегда есть максимальные предупреждения при разработке кода, я никогда не позволяю предупреждению идти, не понимая, что это значит и каковы последствия. Лично я не забочусь об этом предупреждении. Я знаю, что хочу, и PHP не делает это правильно. Я пришел сюда, чтобы найти способ выборочно подавить его. Я еще не нашел пути.

Поэтому я задержу это предупреждение и подавляю его сам. Позор мне нужно сделать. но я строго отношусь к STRICT.

Ответ 3

Вы можете переопределить параметры, но подпись должна соответствовать. Если вы поставили Array перед $bar, проблем не возникнет.

Например, если вы добавили дополнительный параметр, проблем не возникнет, если первый параметр имеет однотипный намек. Это хорошая практика на любом языке.

Ответ 4

Поскольку вы объявили в Foo, что $bar должен иметь тип array, тогда как в расширении Bar тип $bar не объявляется.

Это не ошибка, это предупреждение. Вы должны сделать определение метода совместимым с исходным базовым классом. Вы можете, однако, смело игнорировать его, если знаете, что делаете (и только, если знаете, что делаете!!!)