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


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

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


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), вы также получите эту ошибку, даже если параметры метода идентичны.


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». На самом деле они оба делают то же самое, просто возвращая класс, но с разными пространствами имен, как я описывал ранее.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.