Объявление методов должно быть совместимо с родительскими методами в PHP

107
Строгие стандарты: объявление childClass :: customMethod () должно быть совместимо с объявлением parentClass :: customMethod ()

Каковы возможные причины этой ошибки в PHP? Где я могу найти информацию о том, что значит быть совместимым ?

waiwai933
источник
notJim совершенно прав. @ waiwai933, если бы вы могли опубликовать заголовки (только первую строку function customMethod( ... )
:)
Более подробная информация о сообщении об ошибке и последствиях для времени компиляции PHP: bugs.php.net/bug.php?id=46851
hakre
1
Моя проблема заключалась в том, что аргумент имел use Closure;подсказку типа, но тогда я не добавлял его в начало своего класса (поскольку подсказка типа была Closure). Итак ... обязательно проверьте, не упускаете ли вы подобные зависимости.
Райан

Ответы:

126

childClass::customMethod()имеет другие аргументы или другой уровень доступа (публичный / частный / защищенный), чем parentClass::customMethod().

Дэвидтбернал
источник
1
вероятно, это потому, что видимость , подпись методов не является проблемой в PHP
Габриэль Соса,
43
Также важно иметь одинаковые точные значения аргументов по умолчанию. Например, parentClass::customMethod($thing = false)и childClass::customMethod($thing)вызовет ошибку, потому что дочерний метод не определил значение по умолчанию для первого аргумента.
Чарльз
1
Я считаю, что видимость - это другая ошибка. Кстати, в моем магазине мы не используем строгий режим из-за этого (мы используем E_ALL, IIRC).
davidtbernal
12
Это было изменено в PHP 5.4, кстати: * E_ALL теперь включает ошибки уровня E_STRICT в директиве конфигурации error_reporting. См. Здесь: php.net/manual/en/migration54.other.php
Дункан Лок
1
Отсутствие амперсанда ( &) в аргументах также может вызвать эту ошибку.
ИванРФ
36

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

class A { public function foo($a = 1) {;}}
class B extends A { public function foo($a) {;}}
function bar(A $a) {$a->foo();}

Компилятор проверяет только вызов $ a-> foo () на соответствие требованиям A :: foo (), который не требует параметров. Однако $ a может быть объектом класса B, которому требуется параметр, поэтому вызов не удастся во время выполнения.

Однако это никогда не может потерпеть неудачу и не вызывает ошибку.

class A { public function foo($a) {;}}
class B extends A { public function foo($a = 1) {;}}
function bar(A $a) {$a->foo();}

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

Такое же сообщение генерируется, когда подсказки типа не совпадают, но в этом случае PHP еще более строг. Это дает ошибку:

class A { public function foo(StdClass $a) {;}}
class B extends A { public function foo($a) {;}}

как это делает:

class A { public function foo($a) {;}}
class B extends A { public function foo(StdClass $a) {;}}

Это кажется более строгим, чем нужно, и я предполагаю, что это связано с внутренними особенностями.

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

лдрут
источник
2
в вашем последнем примере - здесь не должно быть ошибки, потому что это законно, stdClass $ a более строгий, чем смешанный $ a. есть способ обойти это? я имею в виду, что в этом случае PHP должен позволять это, но все равно выдает ошибку ...
galchen
2
Ваш последний пример является типобезопасным, поэтому он, безусловно, «более строгий, чем должен быть». Это может быть случай культового программирования, поскольку он конфликтует с полиморфизмом в C ++ и Java en.wikipedia.org/wiki/…
Warbo
спасибо за объяснение, в моем случае первый приведенный вами пример был именно тем, что вызвало мою ошибку.
billynoah
Спасибо вам за это, сэр.
Eldoïr
22

если вы хотите сохранить форму ООП без отключения ошибок, вы также можете:

class A
{
    public function foo() {
        ;
    }
}
class B extends A
{
    /*instead of : 
    public function foo($a, $b, $c) {*/
    public function foo() {
        list($a, $b, $c) = func_get_args();
        // ...

    }
}
Саджад Ширази
источник
Я хотел бы использовать этот прием, чтобы обойти эти ошибки. Я боюсь, что такой подход может снизить производительность? Я изучу это, но если у вас есть ресурсы, которые помогут ответить на этот вопрос, было бы здорово.
Адам Фридман
Думаю, зависит от ситуации. Тем не менее, да, это может быть немного взломано, но это php? уже, иногда это может быть хорошим решением, спасибо! <@
Мастер Джеймс
ты спас мне день! это был единственный вариант безболезненно запустить устаревший проект php5 на сервере с php7
vladkras
В этом случае вы можете использовать значения по умолчанию , вместо того func_get_args(), то есть, в B, public function foo($a = null, $b = null, $c = null)как это не нарушает контракт , обещанный A.
Джейк
1

Просто чтобы расширить эту ошибку в контексте интерфейса, если вы вводите намекающие параметры вашей функции следующим образом:

интерфейс A

use Bar;

interface A
{
    public function foo(Bar $b);
}

Класс B

class B implements A
{
    public function foo(Bar $b);
}

Если вы забыли включить useоператор в свой реализующий класс (класс B), вы также получите эту ошибку, даже если параметры метода идентичны.

Spholt
источник
0

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

Что я хотя

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function whatever(): ClassOfVendor
   {
        return new ClassOfVendor();
   }
}

Что я наконец сделал

namespace mycompany\CutreApi;

use \vendor\AwesomeApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function whatever(): ClassOfVendor
   {
        return new \mycompany\CutreApi\ClassOfVendor();
   }
}

Похоже, что эта ошибка возникает также, когда вы используете метод, возвращающий класс с пространством имен, и пытаетесь вернуть тот же класс, но с другим пространством имен. К счастью, я нашел это решение, но я не до конца понимаю преимущества этой функции в php 7.2, для меня нормально переписывать существующие методы класса по мере необходимости, включая переопределение входных параметров и / или даже поведения метод.

Одним из недостатков предыдущего подхода является то, что IDE не могла распознать новые методы, реализованные в \ mycompany \ CutreApi \ ClassOfVendor (). Итак, пока я перейду к этой реализации.

В настоящее время сделано

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function getWhatever(): ClassOfVendor
   {
        return new ClassOfVendor();
   }
}

Итак, вместо того, чтобы пытаться использовать «любой» метод, я написал новый под названием «getWhatever». На самом деле они оба делают то же самое, просто возвращая класс, но с разными пространствами имен, как я описывал ранее.

Надеюсь, это кому-то поможет.

Ферран
источник