Почему переопределение параметров метода является нарушением строгих стандартов в PHP?
Я знаю, что в StackOverflow есть несколько подобных вопросов, например этот вопрос.
Почему переопределение параметров метода является нарушением строгих стандартов в PHP?
Например:
class Foo
{
public function bar(Array $bar){}
}
class Baz extends Foo
{
public function bar($bar) {}
}
Строгие стандарты: декларация Baz:: bar() должна быть совместима с Foo:: bar()
На других языках программирования ООП вы можете. Почему это плохо в PHP?
Ответы
Ответ 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
не объявляется.
Это не ошибка, это предупреждение. Вы должны сделать определение метода совместимым с исходным базовым классом. Вы можете, однако, смело игнорировать его, если знаете, что делаете (и только, если знаете, что делаете!!!)